1 /* 2 * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package test.javafx.scene.control; 27 28 import static com.sun.xml.internal.fastinfoset.alphabet.BuiltInRestrictedAlphabets.table; 29 import static test.com.sun.javafx.scene.control.infrastructure.ControlTestUtils.assertStyleClassContains; 30 import static javafx.scene.control.TreeTableColumn.SortType.ASCENDING; 31 import static javafx.scene.control.TreeTableColumn.SortType.DESCENDING; 32 import static org.junit.Assert.*; 33 import static org.junit.Assert.assertEquals; 34 35 import java.util.ArrayList; 36 import java.util.Comparator; 37 import java.util.List; 38 import java.util.Objects; 39 import java.util.concurrent.atomic.AtomicInteger; 40 import java.util.function.Supplier; 41 import java.util.stream.Collectors; 42 43 import com.sun.javafx.scene.control.behavior.TreeTableCellBehavior; 44 import javafx.beans.property.ReadOnlyIntegerWrapper; 45 import javafx.collections.transformation.FilteredList; 46 import javafx.scene.control.TableColumn; 47 import javafx.scene.control.TableView; 48 import test.com.sun.javafx.scene.control.infrastructure.KeyEventFirer; 49 import test.com.sun.javafx.scene.control.infrastructure.KeyModifier; 50 import test.com.sun.javafx.scene.control.infrastructure.MouseEventFirer; 51 import javafx.scene.control.skin.TreeTableCellSkin; 52 import test.com.sun.javafx.scene.control.test.Data; 53 54 import javafx.application.Platform; 55 import javafx.beans.InvalidationListener; 56 import javafx.beans.Observable; 57 import javafx.beans.binding.Bindings; 58 import javafx.beans.binding.ObjectBinding; 59 import javafx.beans.property.ObjectProperty; 60 import javafx.beans.property.ReadOnlyBooleanWrapper; 61 import javafx.beans.property.ReadOnlyObjectWrapper; 62 import javafx.beans.property.ReadOnlyStringWrapper; 63 import javafx.beans.property.SimpleObjectProperty; 64 import javafx.beans.property.SimpleStringProperty; 65 import javafx.collections.FXCollections; 66 import javafx.collections.ListChangeListener; 67 import javafx.collections.ObservableList; 68 import javafx.event.EventHandler; 69 import javafx.scene.Group; 70 import javafx.scene.Node; 71 import javafx.scene.Scene; 72 import javafx.scene.control.TreeTableView.TreeTableViewFocusModel; 73 import javafx.scene.control.cell.*; 74 import javafx.scene.image.ImageView; 75 import javafx.scene.input.KeyCode; 76 import javafx.scene.layout.StackPane; 77 import javafx.scene.layout.VBox; 78 import javafx.scene.paint.Color; 79 import javafx.scene.shape.Circle; 80 import javafx.scene.shape.Rectangle; 81 import javafx.stage.Stage; 82 import javafx.util.Callback; 83 84 import org.junit.Before; 85 import org.junit.Ignore; 86 import org.junit.Test; 87 88 import com.sun.javafx.scene.control.TableColumnComparatorBase.TreeTableColumnComparator; 89 import test.com.sun.javafx.scene.control.infrastructure.ControlTestUtils; 90 import test.com.sun.javafx.scene.control.infrastructure.StageLoader; 91 import test.com.sun.javafx.scene.control.infrastructure.VirtualFlowTestUtils; 92 import com.sun.javafx.scene.control.VirtualScrollBar; 93 import test.com.sun.javafx.scene.control.test.Person; 94 import test.com.sun.javafx.scene.control.test.RT_22463_Person; 95 import com.sun.javafx.tk.Toolkit; 96 import javafx.scene.control.Button; 97 import javafx.scene.control.Cell; 98 import javafx.scene.control.FocusModel; 99 import javafx.scene.control.IndexedCell; 100 import javafx.scene.control.MultipleSelectionModel; 101 import javafx.scene.control.MultipleSelectionModelBaseShim; 102 import javafx.scene.control.SelectionMode; 103 import javafx.scene.control.TableColumnBaseShim; 104 import javafx.scene.control.TableSelectionModel; 105 import javafx.scene.control.TextField; 106 import javafx.scene.control.TreeItem; 107 import javafx.scene.control.TreeTableCell; 108 import javafx.scene.control.TreeTableCellShim; 109 import javafx.scene.control.TreeTableColumn; 110 import javafx.scene.control.TreeTablePosition; 111 import javafx.scene.control.TreeTableRow; 112 import javafx.scene.control.TreeTableRowShim; 113 import javafx.scene.control.TreeTableView; 114 import javafx.scene.control.TreeTableViewShim; 115 import javafx.scene.control.TreeView; 116 117 public class TreeTableViewTest { 118 private TreeTableView<String> treeTableView; 119 private TreeTableView.TreeTableViewSelectionModel sm; 120 private TreeTableViewFocusModel<String> fm; 121 122 123 // sample data #1 124 private TreeItem<String> root; 125 private TreeItem<String> child1; 126 private TreeItem<String> child2; 127 private TreeItem<String> child3; 128 129 // sample data #1 130 private TreeItem<String> myCompanyRootNode; 131 private TreeItem<String> salesDepartment; 132 private TreeItem<String> ethanWilliams; 133 private TreeItem<String> emmaJones; 134 private TreeItem<String> michaelBrown; 135 private TreeItem<String> annaBlack; 136 private TreeItem<String> rodgerYork; 137 private TreeItem<String> susanCollins; 138 139 private TreeItem<String> itSupport; 140 private TreeItem<String> mikeGraham; 141 private TreeItem<String> judyMayer; 142 private TreeItem<String> gregorySmith; 143 144 @Before public void setup() { 145 treeTableView = new TreeTableView<String>(); 146 sm = treeTableView.getSelectionModel(); 147 fm = treeTableView.getFocusModel(); 148 149 // build sample data #2, even though it may not be used... 150 myCompanyRootNode = new TreeItem<String>("MyCompany Human Resources"); 151 salesDepartment = new TreeItem<String>("Sales Department"); 152 ethanWilliams = new TreeItem<String>("Ethan Williams"); 153 emmaJones = new TreeItem<String>("Emma Jones"); 154 michaelBrown = new TreeItem<String>("Michael Brown"); 155 annaBlack = new TreeItem<String>("Anna Black"); 156 rodgerYork = new TreeItem<String>("Rodger York"); 157 susanCollins = new TreeItem<String>("Susan Collins"); 158 159 itSupport = new TreeItem<String>("IT Support"); 160 mikeGraham = new TreeItem<String>("Mike Graham"); 161 judyMayer = new TreeItem<String>("Judy Mayer"); 162 gregorySmith = new TreeItem<String>("Gregory Smith"); 163 164 myCompanyRootNode.getChildren().setAll( 165 salesDepartment, 166 itSupport 167 ); 168 salesDepartment.getChildren().setAll( 169 ethanWilliams, 170 emmaJones, 171 michaelBrown, 172 annaBlack, 173 rodgerYork, 174 susanCollins 175 ); 176 itSupport.getChildren().setAll( 177 mikeGraham, 178 judyMayer, 179 gregorySmith 180 ); 181 } 182 183 private void installChildren() { 184 root = new TreeItem<String>("Root"); 185 child1 = new TreeItem<String>("Child 1"); 186 child2 = new TreeItem<String>("Child 2"); 187 child3 = new TreeItem<String>("Child 3"); 188 root.setExpanded(true); 189 root.getChildren().setAll(child1, child2, child3); 190 treeTableView.setRoot(root); 191 } 192 193 private String debug() { 194 StringBuilder sb = new StringBuilder("Selected Cells: ["); 195 196 List<TreeTablePosition<?,?>> cells = sm.getSelectedCells(); 197 for (TreeTablePosition cell : cells) { 198 sb.append("("); 199 sb.append(cell.getRow()); 200 sb.append(","); 201 sb.append(cell.getColumn()); 202 sb.append("), "); 203 } 204 205 sb.append("] \nFocus: " + fm.getFocusedIndex()); 206 // sb.append(" \nAnchor: " + getAnchor()); 207 return sb.toString(); 208 } 209 210 @Test public void ensureCorrectInitialState() { 211 installChildren(); 212 assertEquals(0, treeTableView.getRow(root)); 213 assertEquals(1, treeTableView.getRow(child1)); 214 assertEquals(2, treeTableView.getRow(child2)); 215 assertEquals(3, treeTableView.getRow(child3)); 216 } 217 218 219 220 221 222 223 224 225 /*************************************************************************** 226 * 227 * 228 * Tests taken from TableViewTest 229 * (scroll down further for the TreeViewTests) 230 * 231 * 232 **************************************************************************/ 233 234 /********************************************************************* 235 * Tests for the constructors * 236 ********************************************************************/ 237 238 @Test public void noArgConstructorSetsNonNullSelectionModel() { 239 assertNotNull(sm); 240 } 241 242 @Test public void noArgConstructor_selectedItemIsNull() { 243 assertNull(sm.getSelectedItem()); 244 } 245 246 @Test public void noArgConstructor_selectedIndexIsNegativeOne() { 247 assertEquals(-1, sm.getSelectedIndex()); 248 } 249 250 @Test public void noArgConstructorSetsNonNullSortPolicy() { 251 assertNotNull(treeTableView.getSortPolicy()); 252 } 253 254 @Test public void noArgConstructorSetsNullComparator() { 255 assertNull(treeTableView.getComparator()); 256 } 257 258 @Test public void noArgConstructorSetsNullOnSort() { 259 assertNull(treeTableView.getOnSort()); 260 } 261 262 // @Test public void singleArgConstructorSetsNonNullSelectionModel() { 263 // final TreeTableView<String> b2 = new TreeTableView<String>(FXCollections.observableArrayList("Hi")); 264 // assertNotNull(b2.getSelectionModel()); 265 // } 266 // 267 // @Test public void singleArgConstructorAllowsNullItems() { 268 // final TreeTableView<String> b2 = new TreeTableView<String>(null); 269 // assertNull(b2.getItems()); 270 // } 271 // 272 // @Test public void singleArgConstructorTakesItems() { 273 // ObservableList<String> items = FXCollections.observableArrayList("Hi"); 274 // final TreeTableView<String> b2 = new TreeTableView<String>(items); 275 // assertSame(items, b2.getItems()); 276 // } 277 // 278 // @Test public void singleArgConstructor_selectedItemIsNull() { 279 // final TreeTableView<String> b2 = new TreeTableView<String>(FXCollections.observableArrayList("Hi")); 280 // assertNull(b2.getSelectionModel().getSelectedItem()); 281 // } 282 // 283 // @Test public void singleArgConstructor_selectedIndexIsNegativeOne() { 284 // final TreeTableView<String> b2 = new TreeTableView<String>(FXCollections.observableArrayList("Hi")); 285 // assertEquals(-1, b2.getSelectionModel().getSelectedIndex()); 286 // } 287 288 /********************************************************************* 289 * Tests for columns * 290 ********************************************************************/ 291 292 @Test public void testColumns() { 293 TreeTableColumn col1 = new TreeTableColumn(); 294 295 assertNotNull(treeTableView.getColumns()); 296 assertEquals(0, treeTableView.getColumns().size()); 297 298 treeTableView.getColumns().add(col1); 299 assertEquals(1, treeTableView.getColumns().size()); 300 301 treeTableView.getColumns().remove(col1); 302 assertEquals(0, treeTableView.getColumns().size()); 303 } 304 305 @Test public void testVisibleLeafColumns() { 306 TreeTableColumn col1 = new TreeTableColumn(); 307 308 assertNotNull(treeTableView.getColumns()); 309 assertEquals(0, treeTableView.getColumns().size()); 310 311 treeTableView.getColumns().add(col1); 312 assertEquals(1, treeTableView.getVisibleLeafColumns().size()); 313 314 treeTableView.getColumns().remove(col1); 315 assertEquals(0, treeTableView.getVisibleLeafColumns().size()); 316 } 317 318 @Test public void testSortOrderCleanup() { 319 TreeTableView treeTableView = new TreeTableView(); 320 TreeTableColumn<String,String> first = new TreeTableColumn<String,String>("first"); 321 first.setCellValueFactory(new PropertyValueFactory("firstName")); 322 TreeTableColumn<String,String> second = new TreeTableColumn<String,String>("second"); 323 second.setCellValueFactory(new PropertyValueFactory("lastName")); 324 treeTableView.getColumns().addAll(first, second); 325 treeTableView.getSortOrder().setAll(first, second); 326 treeTableView.getColumns().remove(first); 327 assertFalse(treeTableView.getSortOrder().contains(first)); 328 } 329 330 331 /********************************************************************* 332 * Tests for new sorting API in JavaFX 8.0 * 333 ********************************************************************/ 334 335 private TreeItem<String> apple, orange, banana; 336 337 // TODO test for sort policies returning null 338 // TODO test for changing column sortType out of order 339 340 private static final Callback<TreeTableView<String>, Boolean> NO_SORT_FAILED_SORT_POLICY = 341 treeTableView1 -> false; 342 343 private static final Callback<TreeTableView<String>, Boolean> SORT_SUCCESS_ASCENDING_SORT_POLICY = 344 treeTableView1 -> { 345 if (treeTableView1.getSortOrder().isEmpty()) return true; 346 FXCollections.sort(treeTableView1.getRoot().getChildren(), new Comparator<TreeItem<String>>() { 347 @Override public int compare(TreeItem<String> o1, TreeItem<String> o2) { 348 return o1.getValue().compareTo(o2.getValue()); 349 } 350 }); 351 return true; 352 }; 353 354 private TreeTableColumn<String, String> initSortTestStructure() { 355 TreeTableColumn<String, String> col = new TreeTableColumn<String, String>("column"); 356 col.setSortType(ASCENDING); 357 col.setCellValueFactory(param -> new ReadOnlyObjectWrapper<String>(param.getValue().getValue())); 358 treeTableView.getColumns().add(col); 359 360 TreeItem<String> newRoot = new TreeItem<String>("root"); 361 newRoot.setExpanded(true); 362 newRoot.getChildren().addAll( 363 apple = new TreeItem("Apple"), 364 orange = new TreeItem("Orange"), 365 banana = new TreeItem("Banana")); 366 367 treeTableView.setRoot(newRoot); 368 369 return col; 370 } 371 372 @Ignore("This test is only valid if sort event consumption should revert changes") 373 @Test public void testSortEventCanBeConsumedToStopSortOccurring_changeSortOrderList() { 374 TreeTableColumn<String, String> col = initSortTestStructure(); 375 treeTableView.setOnSort(event -> { 376 event.consume(); 377 }); 378 379 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 380 treeTableView.getSortOrder().add(col); 381 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 382 383 // the sort order list should be returned back to its original state 384 assertTrue(treeTableView.getSortOrder().isEmpty()); 385 } 386 387 @Test public void testSortEventCanBeNotConsumedToAllowSortToOccur_changeSortOrderList() { 388 TreeTableColumn<String, String> col = initSortTestStructure(); 389 treeTableView.setOnSort(event -> { 390 // do not consume here - this allows the sort to happen 391 }); 392 393 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 394 treeTableView.getSortOrder().add(col); 395 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, banana, orange); 396 397 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getSortOrder(), col); 398 } 399 400 @Ignore("This test is only valid if sort event consumption should revert changes") 401 @Test public void testSortEventCanBeConsumedToStopSortOccurring_changeColumnSortType_AscendingToDescending() { 402 TreeTableColumn<String, String> col = initSortTestStructure(); 403 assertEquals(ASCENDING, col.getSortType()); 404 treeTableView.getSortOrder().add(col); 405 treeTableView.setOnSort(event -> { 406 event.consume(); 407 }); 408 409 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, banana, orange); 410 411 // when we change from ASCENDING to DESCENDING we don't expect the sort 412 // to actually change (and in fact we expect the sort type to resort 413 // back to being ASCENDING) 414 col.setSortType(DESCENDING); 415 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, banana, orange); 416 assertEquals(ASCENDING, col.getSortType()); 417 418 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getSortOrder(), col); 419 } 420 421 @Test public void testSortEventCanBeNotConsumedToAllowSortToOccur_changeColumnSortType_AscendingToDescending() { 422 TreeTableColumn<String, String> col = initSortTestStructure(); 423 assertEquals(ASCENDING, col.getSortType()); 424 treeTableView.getSortOrder().add(col); 425 treeTableView.setOnSort(event -> { 426 // do not consume here - this allows the sort to happen 427 }); 428 429 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, banana, orange); 430 431 col.setSortType(DESCENDING); 432 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), orange, banana, apple); 433 assertEquals(DESCENDING, col.getSortType()); 434 435 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getSortOrder(), col); 436 } 437 438 @Ignore("This test is only valid if sort event consumption should revert changes") 439 @Test public void testSortEventCanBeConsumedToStopSortOccurring_changeColumnSortType_DescendingToNull() { 440 TreeTableColumn<String, String> col = initSortTestStructure(); 441 col.setSortType(DESCENDING); 442 assertEquals(DESCENDING, col.getSortType()); 443 treeTableView.getSortOrder().add(col); 444 treeTableView.setOnSort(event -> { 445 event.consume(); 446 }); 447 448 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), orange, banana, apple); 449 450 col.setSortType(null); 451 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), orange, banana, apple); 452 assertEquals(DESCENDING, col.getSortType()); 453 454 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getSortOrder(), col); 455 } 456 457 @Test public void testSortEventCanBeNotConsumedToAllowSortToOccur_changeColumnSortType_DescendingToNull() { 458 TreeTableColumn<String, String> col = initSortTestStructure(); 459 col.setSortType(DESCENDING); 460 assertEquals(DESCENDING, col.getSortType()); 461 treeTableView.getSortOrder().add(col); 462 treeTableView.setOnSort(event -> { 463 // do not consume here - this allows the sort to happen 464 }); 465 466 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), orange, banana, apple); 467 468 col.setSortType(null); 469 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), orange, banana, apple); 470 assertNull(col.getSortType()); 471 472 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getSortOrder(), col); 473 } 474 475 @Ignore("This test is only valid if sort event consumption should revert changes") 476 @Test public void testSortEventCanBeConsumedToStopSortOccurring_changeColumnSortType_NullToAscending() { 477 TreeTableColumn<String, String> col = initSortTestStructure(); 478 col.setSortType(null); 479 assertNull(col.getSortType()); 480 treeTableView.getSortOrder().add(col); 481 treeTableView.setOnSort(event -> { 482 event.consume(); 483 }); 484 485 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 486 487 col.setSortType(ASCENDING); 488 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 489 assertNull(col.getSortType()); 490 491 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getSortOrder(), col); 492 } 493 494 @Test public void testSortEventCanBeNotConsumedToAllowSortToOccur_changeColumnSortType_NullToAscending() { 495 TreeTableColumn<String, String> col = initSortTestStructure(); 496 col.setSortType(null); 497 assertNull(col.getSortType()); 498 treeTableView.getSortOrder().add(col); 499 treeTableView.setOnSort(event -> { 500 // do not consume here - this allows the sort to happen 501 }); 502 503 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 504 505 col.setSortType(ASCENDING); 506 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, banana, orange); 507 assertEquals(ASCENDING, col.getSortType()); 508 509 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getSortOrder(), col); 510 } 511 512 @Test public void testSortMethodWithNullSortPolicy() { 513 TreeTableColumn<String, String> col = initSortTestStructure(); 514 treeTableView.setSortPolicy(null); 515 assertNull(treeTableView.getSortPolicy()); 516 treeTableView.sort(); 517 } 518 519 @Test public void testChangingSortPolicyUpdatesItemsList() { 520 TreeTableColumn<String, String> col = initSortTestStructure(); 521 col.setSortType(DESCENDING); 522 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 523 treeTableView.getSortOrder().add(col); 524 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), orange, banana, apple); 525 treeTableView.setSortPolicy(SORT_SUCCESS_ASCENDING_SORT_POLICY); 526 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, banana, orange); 527 } 528 529 @Test public void testChangingSortPolicyDoesNotUpdateItemsListWhenTheSortOrderListIsEmpty() { 530 TreeTableColumn<String, String> col = initSortTestStructure(); 531 col.setSortType(DESCENDING); 532 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 533 534 treeTableView.setSortPolicy(SORT_SUCCESS_ASCENDING_SORT_POLICY); 535 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 536 } 537 538 @Test public void testFailedSortPolicyBacksOutLastChange_sortOrderAddition() { 539 TreeTableColumn<String, String> col = initSortTestStructure(); 540 col.setSortType(DESCENDING); 541 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 542 treeTableView.setSortPolicy(NO_SORT_FAILED_SORT_POLICY); 543 544 treeTableView.getSortOrder().add(col); 545 546 // no sort should be run (as we have a custom sort policy), and the 547 // sortOrder list should be empty as the sortPolicy failed 548 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 549 assertTrue(treeTableView.getSortOrder().isEmpty()); 550 } 551 552 @Test public void testFailedSortPolicyBacksOutLastChange_sortOrderRemoval() { 553 TreeTableColumn<String, String> col = initSortTestStructure(); 554 col.setSortType(DESCENDING); 555 treeTableView.getSortOrder().add(col); 556 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), orange, banana, apple); 557 558 treeTableView.setSortPolicy(NO_SORT_FAILED_SORT_POLICY); 559 560 // even though we remove the column from the sort order here, because the 561 // sort policy fails the items list should remain unchanged and the sort 562 // order list should continue to have the column in it. 563 treeTableView.getSortOrder().remove(col); 564 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), orange, banana, apple); 565 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getSortOrder(), col); 566 } 567 568 @Test public void testFailedSortPolicyBacksOutLastChange_sortTypeChange_ascendingToDescending() { 569 TreeTableColumn<String, String> col = initSortTestStructure(); 570 col.setSortType(ASCENDING); 571 treeTableView.getSortOrder().add(col); 572 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, banana, orange); 573 574 treeTableView.setSortPolicy(NO_SORT_FAILED_SORT_POLICY); 575 576 col.setSortType(DESCENDING); 577 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, banana, orange); 578 assertEquals(ASCENDING, col.getSortType()); 579 } 580 581 @Test public void testFailedSortPolicyBacksOutLastChange_sortTypeChange_descendingToNull() { 582 TreeTableColumn<String, String> col = initSortTestStructure(); 583 col.setSortType(DESCENDING); 584 treeTableView.getSortOrder().add(col); 585 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), orange, banana, apple); 586 587 treeTableView.setSortPolicy(NO_SORT_FAILED_SORT_POLICY); 588 589 col.setSortType(null); 590 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), orange, banana, apple); 591 assertEquals(DESCENDING, col.getSortType()); 592 } 593 594 @Test public void testFailedSortPolicyBacksOutLastChange_sortTypeChange_nullToAscending() { 595 TreeTableColumn<String, String> col = initSortTestStructure(); 596 col.setSortType(null); 597 treeTableView.getSortOrder().add(col); 598 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 599 600 treeTableView.setSortPolicy(NO_SORT_FAILED_SORT_POLICY); 601 602 col.setSortType(ASCENDING); 603 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 604 assertNull(col.getSortType()); 605 } 606 607 @Test public void testComparatorChangesInSyncWithSortOrder_1() { 608 TreeTableColumn<String, String> col = initSortTestStructure(); 609 assertNull(treeTableView.getComparator()); 610 assertTrue(treeTableView.getSortOrder().isEmpty()); 611 612 treeTableView.getSortOrder().add(col); 613 TreeTableColumnComparator c = (TreeTableColumnComparator)treeTableView.getComparator(); 614 assertNotNull(c); 615 VirtualFlowTestUtils.assertListContainsItemsInOrder(c.getColumns(), col); 616 } 617 618 @Test public void testComparatorChangesInSyncWithSortOrder_2() { 619 // same as test above 620 TreeTableColumn<String, String> col = initSortTestStructure(); 621 assertNull(treeTableView.getComparator()); 622 assertTrue(treeTableView.getSortOrder().isEmpty()); 623 624 treeTableView.getSortOrder().add(col); 625 TreeTableColumnComparator c = (TreeTableColumnComparator)treeTableView.getComparator(); 626 assertNotNull(c); 627 VirtualFlowTestUtils.assertListContainsItemsInOrder(c.getColumns(), col); 628 629 // now remove column from sort order, and the comparator should go to 630 // being null 631 treeTableView.getSortOrder().remove(col); 632 assertNull(treeTableView.getComparator()); 633 } 634 635 @Test public void testFailedSortPolicyBacksOutComparatorChange_sortOrderAddition() { 636 TreeTableColumn<String, String> col = initSortTestStructure(); 637 final TreeTableColumnComparator oldComparator = (TreeTableColumnComparator)treeTableView.getComparator(); 638 639 col.setSortType(DESCENDING); 640 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), apple, orange, banana); 641 treeTableView.setSortPolicy(NO_SORT_FAILED_SORT_POLICY); 642 643 treeTableView.getSortOrder().add(col); 644 645 assertEquals(oldComparator, treeTableView.getComparator()); 646 } 647 648 @Test public void testFailedSortPolicyBacksOutComparatorChange_sortOrderRemoval() { 649 TreeTableColumn<String, String> col = initSortTestStructure(); 650 TreeTableColumnComparator oldComparator = (TreeTableColumnComparator)treeTableView.getComparator(); 651 assertNull(oldComparator); 652 653 col.setSortType(DESCENDING); 654 treeTableView.getSortOrder().add(col); 655 VirtualFlowTestUtils.assertListContainsItemsInOrder(treeTableView.getRoot().getChildren(), orange, banana, apple); 656 oldComparator = (TreeTableColumnComparator)treeTableView.getComparator(); 657 VirtualFlowTestUtils.assertListContainsItemsInOrder(oldComparator.getColumns(), col); 658 659 treeTableView.setSortPolicy(NO_SORT_FAILED_SORT_POLICY); 660 treeTableView.getSortOrder().remove(col); 661 662 assertTrue(treeTableView.getSortOrder().contains(col)); 663 VirtualFlowTestUtils.assertListContainsItemsInOrder(oldComparator.getColumns(), col); 664 } 665 666 @Test public void testFailedSortPolicyBacksOutComparatorChange_sortTypeChange() { 667 TreeTableColumn<String, String> col = initSortTestStructure(); 668 final TreeTableColumnComparator oldComparator = (TreeTableColumnComparator)treeTableView.getComparator(); 669 assertNull(oldComparator); 670 671 treeTableView.setSortPolicy(NO_SORT_FAILED_SORT_POLICY); 672 treeTableView.getSortOrder().add(col); 673 col.setSortType(ASCENDING); 674 675 assertTrue(treeTableView.getSortOrder().isEmpty()); 676 assertNull(oldComparator); 677 } 678 679 680 681 /********************************************************************* 682 * Tests for specific bugs * 683 ********************************************************************/ 684 // @Test public void test_rt16019() { 685 // // RT-16019: NodeMemory TableView tests fail with 686 // // IndexOutOfBoundsException (ObservableListWrapper.java:336) 687 // TreeTableView treeTableView = new TreeTableView(); 688 // for (int i = 0; i < 1000; i++) { 689 // treeTableView.getItems().add("data " + i); 690 // } 691 // } 692 // 693 // @Test public void test_rt15793() { 694 // // ListView/TableView selectedIndex is 0 although the items list is empty 695 // final TreeTableView tv = new TreeTableView(); 696 // final ObservableList list = FXCollections.observableArrayList(); 697 // tv.setItems(list); 698 // list.add("toto"); 699 // tv.getSelectionModel().select(0); 700 // assertEquals(0, tv.getSelectionModel().getSelectedIndex()); 701 // list.remove(0); 702 // assertEquals(-1, tv.getSelectionModel().getSelectedIndex()); 703 // } 704 // 705 // @Test public void test_rt17522_focusShouldMoveWhenItemAddedAtFocusIndex() { 706 // final TreeTableView lv = new TreeTableView(); 707 // FocusModel fm = lv.getFocusModel(); 708 // lv.getItems().add("row1"); 709 // fm.focus(0); 710 // assertTrue(fm.isFocused(0)); 711 // 712 // lv.getItems().add(0, "row0"); 713 // assertTrue(fm.isFocused(1)); 714 // } 715 // 716 // @Test public void test_rt17522_focusShouldMoveWhenItemAddedBeforeFocusIndex() { 717 // final TreeTableView lv = new TreeTableView(); 718 // FocusModel fm = lv.getFocusModel(); 719 // lv.getItems().addAll("row1", "row2"); 720 // fm.focus(1); 721 // assertTrue(fm.isFocused(1)); 722 // assertEquals("row2", fm.getFocusedItem()); 723 // 724 // lv.getItems().add(1, "row0"); 725 // assertTrue(fm.isFocused(2)); 726 // assertEquals("row2", fm.getFocusedItem()); 727 // assertFalse(fm.isFocused(1)); 728 // } 729 // 730 // @Test public void test_rt17522_focusShouldNotMoveWhenItemAddedAfterFocusIndex() { 731 // final TreeTableView lv = new TreeTableView(); 732 // FocusModel fm = lv.getFocusModel(); 733 // lv.getItems().addAll("row1"); 734 // fm.focus(0); 735 // assertTrue(fm.isFocused(0)); 736 // assertEquals("row1", fm.getFocusedItem()); 737 // 738 // lv.getItems().add(1, "row2"); 739 // assertTrue(fm.isFocused(0)); 740 // assertEquals("row1", fm.getFocusedItem()); 741 // assertFalse(fm.isFocused(1)); 742 // } 743 // 744 // @Test public void test_rt17522_focusShouldBeResetWhenFocusedItemIsRemoved() { 745 // final TreeTableView lv = new TreeTableView(); 746 // FocusModel fm = lv.getFocusModel(); 747 // lv.getItems().add("row1"); 748 // fm.focus(0); 749 // assertTrue(fm.isFocused(0)); 750 // 751 // lv.getItems().remove("row1"); 752 // assertTrue(fm.getFocusedIndex() == -1); 753 // assertNull(fm.getFocusedItem()); 754 // } 755 // 756 // @Test public void test_rt17522_focusShouldMoveWhenItemRemovedBeforeFocusIndex() { 757 // final TreeTableView lv = new TreeTableView(); 758 // FocusModel fm = lv.getFocusModel(); 759 // lv.getItems().addAll("row1", "row2"); 760 // fm.focus(1); 761 // assertTrue(fm.isFocused(1)); 762 // assertEquals("row2", fm.getFocusedItem()); 763 // 764 // lv.getItems().remove("row1"); 765 // assertTrue(fm.isFocused(0)); 766 // assertEquals("row2", fm.getFocusedItem()); 767 // } 768 // 769 // @Test public void test_rt17522_focusShouldNotMoveWhenItemRemovedAfterFocusIndex() { 770 // final TreeTableView lv = new TreeTableView(); 771 // FocusModel fm = lv.getFocusModel(); 772 // lv.getItems().addAll("row1", "row2"); 773 // fm.focus(0); 774 // assertTrue(fm.isFocused(0)); 775 // assertEquals("row1", fm.getFocusedItem()); 776 // 777 // lv.getItems().remove("row2"); 778 // assertTrue(fm.isFocused(0)); 779 // assertEquals("row1", fm.getFocusedItem()); 780 // } 781 // 782 // @Test public void test_rt18385() { 783 // treeTableView.getItems().addAll("row1", "row2", "row3"); 784 // sm.select(1); 785 // treeTableView.getItems().add("Another Row"); 786 // assertEquals(1, sm.getSelectedIndices().size()); 787 // assertEquals(1, sm.getSelectedItems().size()); 788 // assertEquals(1, sm.getSelectedCells().size()); 789 // } 790 791 @Test public void test_rt18339_onlyEditWhenTableViewIsEditable_tableEditableIsFalse_columnEditableIsFalse() { 792 TreeTableColumn<String,String> first = new TreeTableColumn<String,String>("first"); 793 first.setEditable(false); 794 treeTableView.getColumns().add(first); 795 treeTableView.setEditable(false); 796 treeTableView.edit(1, first); 797 assertEquals(null, treeTableView.getEditingCell()); 798 } 799 800 @Test public void test_rt18339_onlyEditWhenTableViewIsEditable_tableEditableIsFalse_columnEditableIsTrue() { 801 TreeTableColumn<String,String> first = new TreeTableColumn<String,String>("first"); 802 first.setEditable(true); 803 treeTableView.getColumns().add(first); 804 treeTableView.setEditable(false); 805 treeTableView.edit(1, first); 806 assertEquals(null, treeTableView.getEditingCell()); 807 } 808 809 @Test public void test_rt18339_onlyEditWhenTableViewIsEditable_tableEditableIsTrue_columnEditableIsFalse() { 810 TreeTableColumn<String,String> first = new TreeTableColumn<String,String>("first"); 811 first.setEditable(false); 812 treeTableView.getColumns().add(first); 813 treeTableView.setEditable(true); 814 treeTableView.edit(1, first); 815 assertEquals(null, treeTableView.getEditingCell()); 816 } 817 818 @Test public void test_rt18339_onlyEditWhenTableViewIsEditable_tableEditableIsTrue_columnEditableIsTrue() { 819 TreeTableColumn<String,String> first = new TreeTableColumn<String,String>("first"); 820 first.setEditable(true); 821 treeTableView.getColumns().add(first); 822 treeTableView.setEditable(true); 823 treeTableView.edit(1, first); 824 assertEquals(new TreeTablePosition(treeTableView, 1, first), treeTableView.getEditingCell()); 825 } 826 827 // @Test public void test_rt14451() { 828 // treeTableView.getItems().addAll("Apple", "Orange", "Banana"); 829 // sm.setSelectionMode(SelectionMode.MULTIPLE); 830 // sm.selectRange(0, 2); // select from 0 (inclusive) to 2 (exclusive) 831 // assertEquals(2, sm.getSelectedIndices().size()); 832 // } 833 // 834 // @Test public void test_rt21586() { 835 // treeTableView.getItems().setAll("Apple", "Orange", "Banana"); 836 // treeTableView.getSelectionModel().select(1); 837 // assertEquals(1, treeTableView.getSelectionModel().getSelectedIndex()); 838 // assertEquals("Orange", treeTableView.getSelectionModel().getSelectedItem()); 839 // 840 // treeTableView.getItems().setAll("Kiwifruit", "Pineapple", "Grape"); 841 // assertEquals(-1, treeTableView.getSelectionModel().getSelectedIndex()); 842 // assertNull(treeTableView.getSelectionModel().getSelectedItem()); 843 // } 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 /*************************************************************************** 860 * 861 * 862 * Tests taken from TreeViewTest 863 * 864 * 865 **************************************************************************/ 866 867 868 869 870 /********************************************************************* 871 * Tests for the constructors * 872 ********************************************************************/ 873 874 @Test public void noArgConstructorSetsTheStyleClass() { 875 assertStyleClassContains(treeTableView, "tree-table-view"); 876 } 877 878 @Test public void noArgConstructorSetsNullItems() { 879 assertNull(treeTableView.getRoot()); 880 } 881 882 @Test public void singleArgConstructorSetsTheStyleClass() { 883 final TreeTableView<String> b2 = new TreeTableView<String>(new TreeItem<String>("Hi")); 884 assertStyleClassContains(b2, "tree-table-view"); 885 } 886 887 /********************************************************************* 888 * Tests for selection model * 889 ********************************************************************/ 890 891 @Test public void selectionModelCanBeNull() { 892 treeTableView.setSelectionModel(null); 893 assertNull(treeTableView.getSelectionModel()); 894 } 895 896 @Test public void selectionModelCanBeBound() { 897 TableSelectionModel<TreeItem<String>> sm = 898 TreeTableViewShim.<String>get_TreeTableViewArrayListSelectionModel(treeTableView); 899 ObjectProperty<TreeTableView.TreeTableViewSelectionModel<String>> other = 900 new SimpleObjectProperty(sm); 901 treeTableView.selectionModelProperty().bind(other); 902 assertSame(sm, treeTableView.getSelectionModel()); 903 } 904 905 @Test public void selectionModelCanBeChanged() { 906 TableSelectionModel<TreeItem<String>> sm = 907 TreeTableViewShim.<String>get_TreeTableViewArrayListSelectionModel(treeTableView); 908 TreeTableViewShim.<String>setSelectionModel(treeTableView, sm); 909 assertSame(sm, treeTableView.getSelectionModel()); 910 } 911 912 @Test public void canSetSelectedItemToAnItemEvenWhenThereAreNoItems() { 913 TreeItem<String> element = new TreeItem<String>("I AM A CRAZY RANDOM STRING"); 914 treeTableView.getSelectionModel().select(element); 915 assertEquals(-1, treeTableView.getSelectionModel().getSelectedIndex()); 916 assertSame(element, treeTableView.getSelectionModel().getSelectedItem()); 917 } 918 919 @Test public void canSetSelectedItemToAnItemNotInTheDataModel() { 920 installChildren(); 921 TreeItem<String> element = new TreeItem<String>("I AM A CRAZY RANDOM STRING"); 922 treeTableView.getSelectionModel().select(element); 923 assertEquals(-1, treeTableView.getSelectionModel().getSelectedIndex()); 924 assertSame(element, treeTableView.getSelectionModel().getSelectedItem()); 925 } 926 927 @Test public void settingTheSelectedItemToAnItemInItemsResultsInTheCorrectSelectedIndex() { 928 installChildren(); 929 treeTableView.getSelectionModel().select(child1); 930 assertEquals(1, treeTableView.getSelectionModel().getSelectedIndex()); 931 assertSame(child1, treeTableView.getSelectionModel().getSelectedItem()); 932 } 933 934 @Ignore("Not yet supported") 935 @Test public void settingTheSelectedItemToANonexistantItemAndThenSettingItemsWhichContainsItResultsInCorrectSelectedIndex() { 936 treeTableView.getSelectionModel().select(child1); 937 installChildren(); 938 assertEquals(1, treeTableView.getSelectionModel().getSelectedIndex()); 939 assertSame(child1, treeTableView.getSelectionModel().getSelectedItem()); 940 } 941 942 @Ignore("Not yet supported") 943 @Test public void ensureSelectionClearsWhenAllItemsAreRemoved_selectIndex0() { 944 installChildren(); 945 treeTableView.getSelectionModel().select(0); 946 treeTableView.setRoot(null); 947 assertEquals(-1, treeTableView.getSelectionModel().getSelectedIndex()); 948 assertEquals(null, treeTableView.getSelectionModel().getSelectedItem()); 949 } 950 951 @Ignore("Not yet supported") 952 @Test public void ensureSelectionClearsWhenAllItemsAreRemoved_selectIndex2() { 953 installChildren(); 954 treeTableView.getSelectionModel().select(2); 955 treeTableView.setRoot(null); 956 assertEquals(-1, treeTableView.getSelectionModel().getSelectedIndex()); 957 assertEquals(null, treeTableView.getSelectionModel().getSelectedItem()); 958 } 959 960 @Ignore("Not yet supported") 961 @Test public void ensureSelectedItemRemainsAccurateWhenItemsAreCleared() { 962 installChildren(); 963 treeTableView.getSelectionModel().select(2); 964 treeTableView.setRoot(null); 965 assertNull(treeTableView.getSelectionModel().getSelectedItem()); 966 assertEquals(-1, treeTableView.getSelectionModel().getSelectedIndex()); 967 968 TreeItem<String> newRoot = new TreeItem<String>("New Root"); 969 TreeItem<String> newChild1 = new TreeItem<String>("New Child 1"); 970 TreeItem<String> newChild2 = new TreeItem<String>("New Child 2"); 971 TreeItem<String> newChild3 = new TreeItem<String>("New Child 3"); 972 newRoot.setExpanded(true); 973 newRoot.getChildren().setAll(newChild1, newChild2, newChild3); 974 treeTableView.setRoot(root); 975 976 treeTableView.getSelectionModel().select(2); 977 assertEquals(newChild2, treeTableView.getSelectionModel().getSelectedItem()); 978 } 979 980 @Test public void ensureSelectionIsCorrectWhenItemsChange() { 981 installChildren(); 982 treeTableView.getSelectionModel().select(0); 983 assertEquals(root, treeTableView.getSelectionModel().getSelectedItem()); 984 985 TreeItem newRoot = new TreeItem<String>("New Root"); 986 treeTableView.setRoot(newRoot); 987 assertEquals(-1, treeTableView.getSelectionModel().getSelectedIndex()); 988 assertNull(treeTableView.getSelectionModel().getSelectedItem()); 989 assertEquals(0, treeTableView.getFocusModel().getFocusedIndex()); 990 assertEquals(newRoot, treeTableView.getFocusModel().getFocusedItem()); 991 } 992 993 @Test public void ensureSelectionRemainsOnBranchWhenExpanded() { 994 installChildren(); 995 root.setExpanded(false); 996 treeTableView.getSelectionModel().select(0); 997 assertTrue(treeTableView.getSelectionModel().isSelected(0)); 998 root.setExpanded(true); 999 assertTrue(treeTableView.getSelectionModel().isSelected(0)); 1000 assertTrue(treeTableView.getSelectionModel().getSelectedItems().contains(root)); 1001 } 1002 1003 /********************************************************************* 1004 * Tests for misc * 1005 ********************************************************************/ 1006 @Test public void ensureRootIndexIsZeroWhenRootIsShowing() { 1007 installChildren(); 1008 assertEquals(0, treeTableView.getRow(root)); 1009 } 1010 1011 @Test public void ensureRootIndexIsNegativeOneWhenRootIsNotShowing() { 1012 installChildren(); 1013 treeTableView.setShowRoot(false); 1014 assertEquals(-1, treeTableView.getRow(root)); 1015 } 1016 1017 @Test public void ensureCorrectIndexWhenRootTreeItemHasParent() { 1018 installChildren(); 1019 treeTableView.setRoot(child1); 1020 assertEquals(-1, treeTableView.getRow(root)); 1021 assertEquals(0, treeTableView.getRow(child1)); 1022 assertEquals(1, treeTableView.getRow(child2)); 1023 assertEquals(2, treeTableView.getRow(child3)); 1024 } 1025 1026 @Test public void ensureCorrectIndexWhenRootTreeItemHasParentAndRootIsNotShowing() { 1027 installChildren(); 1028 treeTableView.setRoot(child1); 1029 treeTableView.setShowRoot(false); 1030 1031 // despite the fact there are children in this tree, in reality none are 1032 // visible as the root node has no children (only siblings), and the 1033 // root node is not visible. 1034 assertEquals(0, treeTableView.getExpandedItemCount()); 1035 1036 assertEquals(-1, treeTableView.getRow(root)); 1037 assertEquals(-1, treeTableView.getRow(child1)); 1038 assertEquals(-1, treeTableView.getRow(child2)); 1039 assertEquals(-1, treeTableView.getRow(child3)); 1040 } 1041 1042 @Test public void ensureCorrectIndexWhenRootTreeItemIsCollapsed() { 1043 installChildren(); 1044 root.setExpanded(false); 1045 assertEquals(0, treeTableView.getRow(root)); 1046 1047 // note that the indices are negative, as these children rows are not 1048 // visible in the tree 1049 assertEquals(-1, treeTableView.getRow(child1)); 1050 assertEquals(-1, treeTableView.getRow(child2)); 1051 assertEquals(-1, treeTableView.getRow(child3)); 1052 } 1053 1054 // @Test public void removingLastTest() { 1055 // TreeTableView tree_view = new TreeTableView(); 1056 // MultipleSelectionModel sm = tree_view.getSelectionModel(); 1057 // TreeItem<String> tree_model = new TreeItem<String>("Root"); 1058 // TreeItem node = new TreeItem("Data item"); 1059 // tree_model.getChildren().add(node); 1060 // tree_view.setRoot(tree_model); 1061 // tree_model.setExpanded(true); 1062 // // select the 'Data item' in the selection model 1063 // sm.select(tree_model.getChildren().get(0)); 1064 // // remove the 'Data item' from the root node 1065 // tree_model.getChildren().remove(sm.getSelectedItem()); 1066 // // assert the there are no selected items any longer 1067 // assertTrue("items: " + sm.getSelectedItem(), sm.getSelectedItems().isEmpty()); 1068 // } 1069 1070 /********************************************************************* 1071 * Tests from bug reports * 1072 ********************************************************************/ 1073 @Ignore @Test public void test_rt17112() { 1074 TreeItem<String> root1 = new TreeItem<String>("Root"); 1075 root1.setExpanded(true); 1076 addChildren(root1, "child"); 1077 for (TreeItem child : root1.getChildren()) { 1078 addChildren(child, (String)child.getValue()); 1079 child.setExpanded(true); 1080 } 1081 1082 final TreeTableView treeTableView1 = new TreeTableView(); 1083 final MultipleSelectionModel sm = treeTableView1.getSelectionModel(); 1084 sm.setSelectionMode(SelectionMode.MULTIPLE); 1085 treeTableView1.setRoot(root1); 1086 1087 final TreeItem<String> rt17112_child1 = root1.getChildren().get(1); 1088 final TreeItem<String> rt17112_child1_0 = rt17112_child1.getChildren().get(0); 1089 final TreeItem<String> rt17112_child2 = root1.getChildren().get(2); 1090 1091 sm.getSelectedItems().addListener(new InvalidationListener() { 1092 int count = 0; 1093 @Override public void invalidated(Observable observable) { 1094 if (count == 0) { 1095 assertEquals(rt17112_child1_0, sm.getSelectedItem()); 1096 assertEquals(1, sm.getSelectedIndices().size()); 1097 assertEquals(6, sm.getSelectedIndex()); 1098 assertTrue(treeTableView1.getFocusModel().isFocused(6)); 1099 } else if (count == 1) { 1100 assertEquals(rt17112_child1, sm.getSelectedItem()); 1101 assertFalse(sm.getSelectedItems().contains(rt17112_child2)); 1102 assertEquals(1, sm.getSelectedIndices().size()); 1103 assertTrue(treeTableView1.getFocusModel().isFocused(5)); 1104 } 1105 count++; 1106 } 1107 }); 1108 1109 // this triggers the first callback above, so that count == 0 1110 sm.select(rt17112_child1_0); 1111 1112 // this triggers the second callback above, so that count == 1 1113 rt17112_child1.setExpanded(false); 1114 } 1115 private void addChildren(TreeItem parent, String name) { 1116 for (int i=0; i<3; i++) { 1117 TreeItem<String> ti = new TreeItem<String>(name+"-"+i); 1118 parent.getChildren().add(ti); 1119 } 1120 } 1121 1122 @Test public void test_rt17522_focusShouldMoveWhenItemAddedAtFocusIndex_1() { 1123 installChildren(); 1124 FocusModel fm = treeTableView.getFocusModel(); 1125 fm.focus(1); // focus on child1 1126 assertTrue(fm.isFocused(1)); 1127 assertEquals(child1, fm.getFocusedItem()); 1128 1129 TreeItem child0 = new TreeItem("child0"); 1130 root.getChildren().add(0, child0); // 0th index == position of child1 in root 1131 1132 assertEquals(child1, fm.getFocusedItem()); 1133 assertTrue(fm.isFocused(2)); 1134 } 1135 1136 @Test public void test_rt17522_focusShouldMoveWhenItemAddedBeforeFocusIndex_1() { 1137 installChildren(); 1138 FocusModel fm = treeTableView.getFocusModel(); 1139 fm.focus(1); // focus on child1 1140 assertTrue(fm.isFocused(1)); 1141 1142 TreeItem child0 = new TreeItem("child0"); 1143 root.getChildren().add(0, child0); 1144 assertTrue("Focused index: " + fm.getFocusedIndex(), fm.isFocused(2)); 1145 } 1146 1147 @Test public void test_rt17522_focusShouldNotMoveWhenItemAddedAfterFocusIndex_1() { 1148 installChildren(); 1149 FocusModel fm = treeTableView.getFocusModel(); 1150 fm.focus(1); // focus on child1 1151 assertTrue(fm.isFocused(1)); 1152 1153 TreeItem child4 = new TreeItem("child4"); 1154 root.getChildren().add(3, child4); 1155 assertTrue("Focused index: " + fm.getFocusedIndex(), fm.isFocused(1)); 1156 } 1157 1158 @Test public void test_rt17522_focusShouldBeMovedWhenFocusedItemIsRemoved_1() { 1159 installChildren(); 1160 FocusModel fm = treeTableView.getFocusModel(); 1161 fm.focus(1); 1162 assertTrue(fm.isFocused(1)); 1163 1164 root.getChildren().remove(child1); 1165 assertEquals(0, fm.getFocusedIndex()); 1166 assertEquals(treeTableView.getTreeItem(0), fm.getFocusedItem()); 1167 } 1168 1169 @Test public void test_rt17522_focusShouldMoveWhenItemRemovedBeforeFocusIndex_1() { 1170 installChildren(); 1171 FocusModel fm = treeTableView.getFocusModel(); 1172 fm.focus(2); 1173 assertTrue(fm.isFocused(2)); 1174 1175 root.getChildren().remove(child1); 1176 assertTrue(fm.isFocused(1)); 1177 assertEquals(child2, fm.getFocusedItem()); 1178 } 1179 1180 // This test fails as, in TreeTableView FocusModel, we do not know the index of the 1181 // removed tree items, which means we don't know whether they existed before 1182 // or after the focused item. 1183 // @Test public void test_rt17522_focusShouldNotMoveWhenItemRemovedAfterFocusIndex() { 1184 // installChildren(); 1185 // FocusModel fm = treeTableView.getFocusModel(); 1186 // fm.focus(1); 1187 // assertTrue(fm.isFocused(1)); 1188 // 1189 // root.getChildren().remove(child3); 1190 // assertTrue("Focused index: " + fm.getFocusedIndex(), fm.isFocused(1)); 1191 // assertEquals(child1, fm.getFocusedItem()); 1192 // } 1193 1194 @Test public void test_rt18385() { 1195 installChildren(); 1196 // table.getItems().addAll("row1", "row2", "row3"); 1197 treeTableView.getSelectionModel().select(1); 1198 treeTableView.getRoot().getChildren().add(new TreeItem("Another Row")); 1199 assertEquals(1, treeTableView.getSelectionModel().getSelectedIndices().size()); 1200 assertEquals(1, treeTableView.getSelectionModel().getSelectedItems().size()); 1201 } 1202 1203 @Test public void test_rt18339_onlyEditWhenTreeTableViewIsEditable_editableIsFalse() { 1204 TreeItem root = new TreeItem("root"); 1205 root.getChildren().setAll( 1206 new TreeItem(new Person("Jacob", "Smith", "jacob.smith@example.com")), 1207 new TreeItem(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 1208 new TreeItem(new Person("Ethan", "Williams", "ethan.williams@example.com")), 1209 new TreeItem(new Person("Emma", "Jones", "emma.jones@example.com")), 1210 new TreeItem(new Person("Michael", "Brown", "michael.brown@example.com"))); 1211 root.setExpanded(true); 1212 1213 TreeTableView<Person> table = new TreeTableView<Person>(root); 1214 1215 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 1216 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 1217 1218 table.setEditable(false); 1219 table.edit(0,firstNameCol); 1220 assertNull(table.getEditingCell()); 1221 } 1222 1223 @Test public void test_rt18339_onlyEditWhenTreeTableViewIsEditable_editableIsTrue() { 1224 TreeItem root = new TreeItem("root"); 1225 root.getChildren().setAll( 1226 new TreeItem(new Person("Jacob", "Smith", "jacob.smith@example.com")), 1227 new TreeItem(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 1228 new TreeItem(new Person("Ethan", "Williams", "ethan.williams@example.com")), 1229 new TreeItem(new Person("Emma", "Jones", "emma.jones@example.com")), 1230 new TreeItem(new Person("Michael", "Brown", "michael.brown@example.com"))); 1231 root.setExpanded(true); 1232 1233 TreeTableView<Person> table = new TreeTableView<Person>(root); 1234 1235 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 1236 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 1237 1238 table.setEditable(true); 1239 table.edit(0,firstNameCol); 1240 assertEquals(root, table.getEditingCell().getTreeItem()); 1241 } 1242 1243 @Test public void test_rt14451() { 1244 installChildren(); 1245 treeTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 1246 treeTableView.getSelectionModel().selectRange(0, 2); // select from 0 (inclusive) to 2 (exclusive) 1247 assertEquals(2, treeTableView.getSelectionModel().getSelectedIndices().size()); 1248 } 1249 1250 @Test public void test_rt21586() { 1251 installChildren(); 1252 treeTableView.getSelectionModel().select(1); 1253 assertEquals(1, treeTableView.getSelectionModel().getSelectedIndex()); 1254 assertEquals(child1, treeTableView.getSelectionModel().getSelectedItem()); 1255 1256 TreeItem root = new TreeItem<String>("New Root"); 1257 TreeItem child1 = new TreeItem<String>("New Child 1"); 1258 TreeItem child2 = new TreeItem<String>("New Child 2"); 1259 TreeItem child3 = new TreeItem<String>("New Child 3"); 1260 root.setExpanded(true); 1261 root.getChildren().setAll(child1, child2, child3); 1262 treeTableView.setRoot(root); 1263 assertEquals(-1, treeTableView.getSelectionModel().getSelectedIndex()); 1264 assertNull(treeTableView.getSelectionModel().getSelectedItem()); 1265 assertEquals(0, treeTableView.getFocusModel().getFocusedIndex()); 1266 assertEquals(root, treeTableView.getFocusModel().getFocusedItem()); 1267 } 1268 1269 @Test public void test_rt27181() { 1270 myCompanyRootNode.setExpanded(true); 1271 treeTableView.setRoot(myCompanyRootNode); 1272 1273 // start test 1274 salesDepartment.setExpanded(true); 1275 treeTableView.getSelectionModel().select(salesDepartment); 1276 1277 assertEquals(1, treeTableView.getFocusModel().getFocusedIndex()); 1278 itSupport.setExpanded(true); 1279 assertEquals(1, treeTableView.getFocusModel().getFocusedIndex()); 1280 } 1281 1282 @Test public void test_rt27185() { 1283 myCompanyRootNode.setExpanded(true); 1284 treeTableView.setRoot(myCompanyRootNode); 1285 1286 // start test 1287 itSupport.setExpanded(true); 1288 treeTableView.getSelectionModel().select(mikeGraham); 1289 1290 assertEquals(mikeGraham, treeTableView.getFocusModel().getFocusedItem()); 1291 salesDepartment.setExpanded(true); 1292 assertEquals(mikeGraham, treeTableView.getFocusModel().getFocusedItem()); 1293 } 1294 1295 @Ignore("Bug hasn't been fixed yet") 1296 @Test public void test_rt28114() { 1297 myCompanyRootNode.setExpanded(true); 1298 treeTableView.setRoot(myCompanyRootNode); 1299 1300 // start test 1301 itSupport.setExpanded(true); 1302 treeTableView.getSelectionModel().select(itSupport); 1303 assertEquals(itSupport, treeTableView.getFocusModel().getFocusedItem()); 1304 assertEquals(itSupport, treeTableView.getSelectionModel().getSelectedItem()); 1305 assertTrue(! itSupport.isLeaf()); 1306 assertTrue(itSupport.isExpanded()); 1307 1308 itSupport.getChildren().remove(mikeGraham); 1309 assertEquals(itSupport, treeTableView.getFocusModel().getFocusedItem()); 1310 assertEquals(itSupport, treeTableView.getSelectionModel().getSelectedItem()); 1311 assertTrue(itSupport.isLeaf()); 1312 assertTrue(!itSupport.isExpanded()); 1313 } 1314 1315 @Test public void test_rt27820_1() { 1316 TreeItem root = new TreeItem("root"); 1317 root.setExpanded(true); 1318 TreeItem child = new TreeItem("child"); 1319 root.getChildren().add(child); 1320 treeTableView.setRoot(root); 1321 1322 treeTableView.getSelectionModel().select(0); 1323 assertEquals(1, treeTableView.getSelectionModel().getSelectedItems().size()); 1324 assertEquals(root, treeTableView.getSelectionModel().getSelectedItem()); 1325 1326 treeTableView.setRoot(null); 1327 assertEquals(0, treeTableView.getSelectionModel().getSelectedItems().size()); 1328 assertNull(treeTableView.getSelectionModel().getSelectedItem()); 1329 } 1330 1331 @Test public void test_rt27820_2() { 1332 TreeItem root = new TreeItem("root"); 1333 root.setExpanded(true); 1334 TreeItem child = new TreeItem("child"); 1335 root.getChildren().add(child); 1336 treeTableView.setRoot(root); 1337 1338 treeTableView.getSelectionModel().select(1); 1339 assertEquals(1, treeTableView.getSelectionModel().getSelectedItems().size()); 1340 assertEquals(child, treeTableView.getSelectionModel().getSelectedItem()); 1341 1342 treeTableView.setRoot(null); 1343 assertEquals(0, treeTableView.getSelectionModel().getSelectedItems().size()); 1344 assertNull(treeTableView.getSelectionModel().getSelectedItem()); 1345 } 1346 1347 @Test public void test_rt28390() { 1348 // There should be no NPE when a TreeTableView is shown and the disclosure 1349 // node is null in a TreeCell 1350 TreeItem root = new TreeItem("root"); 1351 treeTableView.setRoot(root); 1352 1353 // install a custom cell factory that forces the disclosure node to be 1354 // null (because by default a null disclosure node will be replaced by 1355 // a non-null one). 1356 treeTableView.setRowFactory(new Callback() { 1357 @Override public Object call(Object p) { 1358 TreeTableRow treeCell = new TreeTableRowShim() { 1359 { 1360 disclosureNodeProperty().addListener((ov, t, t1) -> { 1361 setDisclosureNode(null); 1362 }); 1363 } 1364 1365 @Override public void updateItem(Object item, boolean empty) { 1366 super.updateItem(item, empty); 1367 setText(item == null ? "" : item.toString()); 1368 } 1369 }; 1370 treeCell.setDisclosureNode(null); 1371 return treeCell; 1372 } 1373 }); 1374 1375 try { 1376 Group group = new Group(); 1377 group.getChildren().setAll(treeTableView); 1378 Scene scene = new Scene(group); 1379 Stage stage = new Stage(); 1380 stage.setScene(scene); 1381 stage.show(); 1382 } catch (NullPointerException e) { 1383 System.out.println("A null disclosure node is valid, so we shouldn't have an NPE here."); 1384 e.printStackTrace(); 1385 assertTrue(false); 1386 } 1387 } 1388 1389 @Ignore("This test begun failing when createDefaultCellImpl was removed from TreeTableViewSkin on 28/3/2013") 1390 @Test public void test_rt28534() { 1391 TreeItem root = new TreeItem("root"); 1392 root.getChildren().setAll( 1393 new TreeItem(new Person("Jacob", "Smith", "jacob.smith@example.com")), 1394 new TreeItem(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 1395 new TreeItem(new Person("Ethan", "Williams", "ethan.williams@example.com")), 1396 new TreeItem(new Person("Emma", "Jones", "emma.jones@example.com")), 1397 new TreeItem(new Person("Michael", "Brown", "michael.brown@example.com"))); 1398 root.setExpanded(true); 1399 1400 TreeTableView<Person> table = new TreeTableView<Person>(root); 1401 1402 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 1403 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 1404 1405 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 1406 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 1407 1408 TreeTableColumn emailCol = new TreeTableColumn("Email"); 1409 emailCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("email")); 1410 1411 table.getColumns().addAll(firstNameCol, lastNameCol, emailCol); 1412 1413 VirtualFlowTestUtils.assertRowsNotEmpty(table, 0, 6); // rows 0 - 6 should be filled 1414 VirtualFlowTestUtils.assertRowsEmpty(table, 6, -1); // rows 6+ should be empty 1415 1416 // now we replace the data and expect the cells that have no data 1417 // to be empty 1418 root.getChildren().setAll( 1419 new TreeItem(new Person("*_*Emma", "Jones", "emma.jones@example.com")), 1420 new TreeItem(new Person("_Michael", "Brown", "michael.brown@example.com"))); 1421 1422 VirtualFlowTestUtils.assertRowsNotEmpty(table, 0, 3); // rows 0 - 3 should be filled 1423 VirtualFlowTestUtils.assertRowsEmpty(table, 3, -1); // rows 3+ should be empty 1424 } 1425 1426 @Test public void test_rt22463() { 1427 final TreeTableView<RT_22463_Person> table = new TreeTableView<RT_22463_Person>(); 1428 table.setTableMenuButtonVisible(true); 1429 TreeTableColumn c1 = new TreeTableColumn("Id"); 1430 TreeTableColumn c2 = new TreeTableColumn("Name"); 1431 c1.setCellValueFactory(new TreeItemPropertyValueFactory<Person, Long>("id")); 1432 c2.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("name")); 1433 table.getColumns().addAll(c1, c2); 1434 1435 RT_22463_Person rootPerson = new RT_22463_Person(); 1436 rootPerson.setName("Root"); 1437 TreeItem<RT_22463_Person> root = new TreeItem<RT_22463_Person>(rootPerson); 1438 root.setExpanded(true); 1439 1440 table.setRoot(root); 1441 1442 // before the change things display fine 1443 RT_22463_Person p1 = new RT_22463_Person(); 1444 p1.setId(1l); 1445 p1.setName("name1"); 1446 RT_22463_Person p2 = new RT_22463_Person(); 1447 p2.setId(2l); 1448 p2.setName("name2"); 1449 root.getChildren().addAll( 1450 new TreeItem<RT_22463_Person>(p1), 1451 new TreeItem<RT_22463_Person>(p2)); 1452 VirtualFlowTestUtils.assertCellTextEquals(table, 1, "1", "name1"); 1453 VirtualFlowTestUtils.assertCellTextEquals(table, 2, "2", "name2"); 1454 1455 // now we change the persons but they are still equal as the ID's don't 1456 // change - but the items list is cleared so the cells should update 1457 RT_22463_Person new_p1 = new RT_22463_Person(); 1458 new_p1.setId(1l); 1459 new_p1.setName("updated name1"); 1460 RT_22463_Person new_p2 = new RT_22463_Person(); 1461 new_p2.setId(2l); 1462 new_p2.setName("updated name2"); 1463 root.getChildren().clear(); 1464 root.getChildren().setAll( 1465 new TreeItem<RT_22463_Person>(new_p1), 1466 new TreeItem<RT_22463_Person>(new_p2)); 1467 VirtualFlowTestUtils.assertCellTextEquals(table, 1, "1", "updated name1"); 1468 VirtualFlowTestUtils.assertCellTextEquals(table, 2, "2", "updated name2"); 1469 } 1470 1471 @Test public void test_rt28637() { 1472 TreeItem<String> s1, s2, s3, s4; 1473 ObservableList<TreeItem<String>> items = FXCollections.observableArrayList( 1474 s1 = new TreeItem<String>("String1"), 1475 s2 = new TreeItem<String>("String2"), 1476 s3 = new TreeItem<String>("String3"), 1477 s4 = new TreeItem<String>("String4")); 1478 1479 final TreeTableView<String> treeTableView = new TreeTableView<String>(); 1480 1481 TreeItem<String> root = new TreeItem<String>("Root"); 1482 root.setExpanded(true); 1483 treeTableView.setRoot(root); 1484 treeTableView.setShowRoot(false); 1485 root.getChildren().addAll(items); 1486 1487 treeTableView.getSelectionModel().select(0); 1488 assertEquals((Object)s1, treeTableView.getSelectionModel().getSelectedItem()); 1489 assertEquals((Object)s1, treeTableView.getSelectionModel().getSelectedItems().get(0)); 1490 assertEquals(0, treeTableView.getSelectionModel().getSelectedIndex()); 1491 1492 root.getChildren().remove(treeTableView.getSelectionModel().getSelectedItem()); 1493 assertEquals((Object)s2, treeTableView.getSelectionModel().getSelectedItem()); 1494 assertEquals((Object)s2, treeTableView.getSelectionModel().getSelectedItems().get(0)); 1495 assertEquals(0, treeTableView.getSelectionModel().getSelectedIndex()); 1496 } 1497 1498 @Test public void test_rt24844() { 1499 // p1 == lowest first name 1500 TreeItem<Person> p0, p1, p2, p3, p4; 1501 1502 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 1503 p3 = new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 1504 p2 = new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 1505 p1 = new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 1506 p0 = new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com")), 1507 p4 = new TreeItem<Person>(new Person("Michael", "Brown", "michael.brown@example.com"))); 1508 1509 TreeTableView<Person> table = new TreeTableView<>(); 1510 1511 TreeItem<Person> root = new TreeItem<Person>(new Person("Root", null, null)); 1512 root.setExpanded(true); 1513 table.setRoot(root); 1514 table.setShowRoot(false); 1515 root.getChildren().setAll(persons); 1516 1517 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 1518 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 1519 1520 // set dummy comparator to lock items in place until new comparator is set 1521 firstNameCol.setComparator((t, t1) -> 0); 1522 1523 table.getColumns().addAll(firstNameCol); 1524 table.getSortOrder().add(firstNameCol); 1525 1526 // ensure the existing order is as expected 1527 assertEquals(p3, root.getChildren().get(0)); 1528 assertEquals(p2, root.getChildren().get(1)); 1529 assertEquals(p1, root.getChildren().get(2)); 1530 assertEquals(p0, root.getChildren().get(3)); 1531 assertEquals(p4, root.getChildren().get(4)); 1532 1533 // set a new comparator 1534 firstNameCol.setComparator((t, t1) -> t.toString().compareTo(t1.toString())); 1535 1536 // ensure the new order is as expected 1537 assertEquals(p0, root.getChildren().get(0)); 1538 assertEquals(p1, root.getChildren().get(1)); 1539 assertEquals(p2, root.getChildren().get(2)); 1540 assertEquals(p3, root.getChildren().get(3)); 1541 assertEquals(p4, root.getChildren().get(4)); 1542 } 1543 1544 @Test public void test_rt29331() { 1545 TreeTableView<Person> table = new TreeTableView<Person>(); 1546 1547 // p1 == lowest first name 1548 TreeItem<Person> p0, p1, p2, p3, p4; 1549 1550 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 1551 firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName")); 1552 1553 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 1554 lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName")); 1555 1556 TreeTableColumn emailCol = new TreeTableColumn("Email"); 1557 emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("email")); 1558 1559 TreeTableColumn parentColumn = new TreeTableColumn<>("Parent"); 1560 parentColumn.getColumns().addAll(firstNameCol, lastNameCol, emailCol); 1561 1562 table.getColumns().addAll(parentColumn); 1563 1564 // table is setup, now hide the 'last name' column 1565 emailCol.setVisible(false); 1566 assertFalse(emailCol.isVisible()); 1567 1568 // reorder columns inside the parent column 1569 parentColumn.getColumns().setAll(emailCol, firstNameCol, lastNameCol); 1570 1571 // the email column should not become visible after this, but it does 1572 assertFalse(emailCol.isVisible()); 1573 } 1574 1575 private int rt29330_count = 0; 1576 @Test public void test_rt29330_1() { 1577 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 1578 new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 1579 new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 1580 new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 1581 new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com")), 1582 new TreeItem<Person>(new Person("Michael", "Brown", "michael.brown@example.com"))); 1583 1584 TreeTableView<Person> table = new TreeTableView<>(); 1585 1586 TreeItem<Person> root = new TreeItem<Person>(new Person("Root", null, null)); 1587 root.setExpanded(true); 1588 table.setRoot(root); 1589 table.setShowRoot(false); 1590 root.getChildren().setAll(persons); 1591 1592 TreeTableColumn parentColumn = new TreeTableColumn<>("Parent"); 1593 table.getColumns().addAll(parentColumn); 1594 1595 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 1596 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 1597 1598 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 1599 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 1600 1601 parentColumn.getColumns().addAll(firstNameCol, lastNameCol); 1602 1603 table.setOnSort(event -> { 1604 rt29330_count++; 1605 }); 1606 1607 // test preconditions 1608 assertEquals(ASCENDING, lastNameCol.getSortType()); 1609 assertEquals(0, rt29330_count); 1610 1611 table.getSortOrder().add(lastNameCol); 1612 assertEquals(1, rt29330_count); 1613 1614 lastNameCol.setSortType(DESCENDING); 1615 assertEquals(2, rt29330_count); 1616 1617 lastNameCol.setSortType(null); 1618 assertEquals(3, rt29330_count); 1619 1620 lastNameCol.setSortType(ASCENDING); 1621 assertEquals(4, rt29330_count); 1622 } 1623 1624 @Test public void test_rt29330_2() { 1625 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 1626 new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 1627 new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 1628 new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 1629 new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com")), 1630 new TreeItem<Person>(new Person("Michael", "Brown", "michael.brown@example.com"))); 1631 1632 TreeTableView<Person> table = new TreeTableView<>(); 1633 1634 TreeItem<Person> root = new TreeItem<Person>(new Person("Root", null, null)); 1635 root.setExpanded(true); 1636 table.setRoot(root); 1637 table.setShowRoot(false); 1638 root.getChildren().setAll(persons); 1639 1640 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 1641 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 1642 1643 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 1644 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 1645 1646 // this test differs from the previous one by installing the parent column 1647 // into the tableview after it has the children added into it 1648 TreeTableColumn parentColumn = new TreeTableColumn<>("Parent"); 1649 parentColumn.getColumns().addAll(firstNameCol, lastNameCol); 1650 table.getColumns().addAll(parentColumn); 1651 1652 table.setOnSort(event -> { 1653 rt29330_count++; 1654 }); 1655 1656 // test preconditions 1657 assertEquals(ASCENDING, lastNameCol.getSortType()); 1658 assertEquals(0, rt29330_count); 1659 1660 table.getSortOrder().add(lastNameCol); 1661 assertEquals(1, rt29330_count); 1662 1663 lastNameCol.setSortType(DESCENDING); 1664 assertEquals(2, rt29330_count); 1665 1666 lastNameCol.setSortType(null); 1667 assertEquals(3, rt29330_count); 1668 1669 lastNameCol.setSortType(ASCENDING); 1670 assertEquals(4, rt29330_count); 1671 } 1672 1673 @Test public void test_rt29313_selectedIndices() { 1674 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 1675 new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 1676 new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 1677 new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 1678 new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com")), 1679 new TreeItem<Person>(new Person("Michael", "Brown", "michael.brown@example.com"))); 1680 1681 TreeTableView<Person> table = new TreeTableView<>(); 1682 1683 TreeItem<Person> root = new TreeItem<Person>(new Person("Root", null, null)); 1684 root.setExpanded(true); 1685 table.setRoot(root); 1686 table.setShowRoot(false); 1687 root.getChildren().setAll(persons); 1688 1689 TableSelectionModel sm = table.getSelectionModel(); 1690 1691 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 1692 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 1693 1694 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 1695 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 1696 1697 TreeTableColumn emailCol = new TreeTableColumn("Email"); 1698 emailCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("email")); 1699 1700 table.getColumns().addAll(firstNameCol, lastNameCol, emailCol); 1701 sm.setCellSelectionEnabled(true); 1702 sm.setSelectionMode(SelectionMode.MULTIPLE); 1703 1704 assertTrue(sm.getSelectedIndices().isEmpty()); 1705 1706 // only (0,0) should be selected, so selected indices should be [0] 1707 sm.select(0, firstNameCol); 1708 assertEquals(1, sm.getSelectedIndices().size()); 1709 1710 // now (0,0) and (1,0) should be selected, so selected indices should be [0, 1] 1711 sm.select(1, firstNameCol); 1712 assertEquals(2, sm.getSelectedIndices().size()); 1713 1714 // now (0,0), (1,0) and (1,1) should be selected, but selected indices 1715 // should remain as [0, 1], as we don't want selected indices to become 1716 // [0,1,1] (which is what RT-29313 is about) 1717 sm.select(1, lastNameCol); 1718 assertEquals(2, sm.getSelectedIndices().size()); 1719 assertEquals(0, sm.getSelectedIndices().get(0)); 1720 assertEquals(1, sm.getSelectedIndices().get(1)); 1721 } 1722 1723 @Test public void test_rt29313_selectedItems() { 1724 TreeItem<Person> p0, p1; 1725 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 1726 p0 = new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 1727 p1 = new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 1728 new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 1729 new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com")), 1730 new TreeItem<Person>(new Person("Michael", "Brown", "michael.brown@example.com"))); 1731 1732 TreeTableView<Person> table = new TreeTableView<>(); 1733 1734 TreeItem<Person> root = new TreeItem<Person>(new Person("Root", null, null)); 1735 root.setExpanded(true); 1736 table.setRoot(root); 1737 table.setShowRoot(false); 1738 root.getChildren().setAll(persons); 1739 1740 TableSelectionModel sm = table.getSelectionModel(); 1741 1742 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 1743 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 1744 1745 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 1746 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 1747 1748 TreeTableColumn emailCol = new TreeTableColumn("Email"); 1749 emailCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("email")); 1750 1751 table.getColumns().addAll(firstNameCol, lastNameCol, emailCol); 1752 sm.setCellSelectionEnabled(true); 1753 sm.setSelectionMode(SelectionMode.MULTIPLE); 1754 1755 assertTrue(sm.getSelectedItems().isEmpty()); 1756 1757 // only (0,0) should be selected, so selected items should be [p0] 1758 sm.select(0, firstNameCol); 1759 assertEquals(1, sm.getSelectedItems().size()); 1760 1761 // now (0,0) and (1,0) should be selected, so selected items should be [p0, p1] 1762 sm.select(1, firstNameCol); 1763 assertEquals(2, sm.getSelectedItems().size()); 1764 1765 // now (0,0), (1,0) and (1,1) should be selected, but selected items 1766 // should remain as [p0, p1], as we don't want selected items to become 1767 // [p0,p1,p1] (which is what RT-29313 is about) 1768 sm.select(1, lastNameCol); 1769 assertEquals(2, sm.getSelectedItems().size()); 1770 assertEquals(p0, sm.getSelectedItems().get(0)); 1771 assertEquals(p1, sm.getSelectedItems().get(1)); 1772 } 1773 1774 @Test public void test_rt29566() { 1775 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 1776 new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 1777 new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 1778 new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 1779 new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com")), 1780 new TreeItem<Person>(new Person("Michael", "Brown", "michael.brown@example.com"))); 1781 1782 TreeTableView<Person> table = new TreeTableView<>(); 1783 1784 TreeItem<Person> root = new TreeItem<Person>(new Person("Root", null, null)); 1785 root.setExpanded(true); 1786 table.setRoot(root); 1787 table.setShowRoot(false); 1788 root.getChildren().setAll(persons); 1789 1790 TableSelectionModel sm = table.getSelectionModel(); 1791 1792 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 1793 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 1794 1795 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 1796 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 1797 1798 TreeTableColumn emailCol = new TreeTableColumn("Email"); 1799 emailCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("email")); 1800 1801 table.getColumns().addAll(firstNameCol, lastNameCol, emailCol); 1802 1803 // test the state before we hide and re-add a column 1804 VirtualFlowTestUtils.assertCellTextEquals(table, 0, "Jacob", "Smith", "jacob.smith@example.com"); 1805 VirtualFlowTestUtils.assertCellTextEquals(table, 1, "Isabella", "Johnson", "isabella.johnson@example.com"); 1806 VirtualFlowTestUtils.assertCellTextEquals(table, 2, "Ethan", "Williams", "ethan.williams@example.com"); 1807 VirtualFlowTestUtils.assertCellTextEquals(table, 3, "Emma", "Jones", "emma.jones@example.com"); 1808 VirtualFlowTestUtils.assertCellTextEquals(table, 4, "Michael", "Brown", "michael.brown@example.com"); 1809 1810 // hide the last name column, and test cells again 1811 table.getColumns().remove(lastNameCol); 1812 VirtualFlowTestUtils.assertCellTextEquals(table, 0, "Jacob", "jacob.smith@example.com"); 1813 VirtualFlowTestUtils.assertCellTextEquals(table, 1, "Isabella", "isabella.johnson@example.com"); 1814 VirtualFlowTestUtils.assertCellTextEquals(table, 2, "Ethan", "ethan.williams@example.com"); 1815 VirtualFlowTestUtils.assertCellTextEquals(table, 3, "Emma", "emma.jones@example.com"); 1816 VirtualFlowTestUtils.assertCellTextEquals(table, 4, "Michael", "michael.brown@example.com"); 1817 1818 // re-add the last name column - we should go back to the original state. 1819 // However, what appears to be happening is that, for some reason, some 1820 // of the cells from the removed column do not reappear - meaning in this case 1821 // some of the last name values will not be where we expect them to be. 1822 // This is clearly not ideal! 1823 table.getColumns().add(1, lastNameCol); 1824 VirtualFlowTestUtils.assertCellTextEquals(table, 0, "Jacob", "Smith", "jacob.smith@example.com"); 1825 VirtualFlowTestUtils.assertCellTextEquals(table, 1, "Isabella", "Johnson", "isabella.johnson@example.com"); 1826 VirtualFlowTestUtils.assertCellTextEquals(table, 2, "Ethan", "Williams", "ethan.williams@example.com"); 1827 VirtualFlowTestUtils.assertCellTextEquals(table, 3, "Emma", "Jones", "emma.jones@example.com"); 1828 VirtualFlowTestUtils.assertCellTextEquals(table, 4, "Michael", "Brown", "michael.brown@example.com"); 1829 } 1830 1831 @Test public void test_rt29390() { 1832 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 1833 new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 1834 new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 1835 new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 1836 new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com")), 1837 new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 1838 new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 1839 new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 1840 new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com")), 1841 new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 1842 new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 1843 new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 1844 new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com")), 1845 new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 1846 new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 1847 new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 1848 new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com") 1849 )); 1850 1851 TreeTableView<Person> table = new TreeTableView<>(); 1852 table.setMaxHeight(50); 1853 table.setPrefHeight(50); 1854 1855 TreeItem<Person> root = new TreeItem<Person>(new Person("Root", null, null)); 1856 root.setExpanded(true); 1857 table.setRoot(root); 1858 table.setShowRoot(false); 1859 root.getChildren().setAll(persons); 1860 1861 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 1862 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 1863 1864 table.getColumns().add(firstNameCol); 1865 1866 Toolkit.getToolkit().firePulse(); 1867 1868 // we want the vertical scrollbar 1869 VirtualScrollBar scrollBar = VirtualFlowTestUtils.getVirtualFlowVerticalScrollbar(table); 1870 1871 assertNotNull(scrollBar); 1872 assertTrue(scrollBar.isVisible()); 1873 assertTrue(scrollBar.getVisibleAmount() > 0.0); 1874 assertTrue(scrollBar.getVisibleAmount() < 1.0); 1875 1876 // this next test is likely to be brittle, but we'll see...If it is the 1877 // cause of failure then it can be commented out 1878 assertEquals(0.0625, scrollBar.getVisibleAmount(), 0.0); 1879 } 1880 1881 @Test public void test_rt29676_withText() { 1882 // set up test 1883 TreeTableView<Data> treeTableView = new TreeTableView<Data>(); 1884 treeTableView.setMaxWidth(100); 1885 1886 TreeItem<Data> root = new TreeItem<Data>(new Data("Root")); 1887 treeTableView.setRoot(root); 1888 addLevel(root, 0, 30); 1889 1890 treeTableView.getRoot().setExpanded(true); 1891 TreeTableColumn<Data, String> column = new TreeTableColumn<Data, String>("Items' name"); 1892 column.setCellValueFactory(p -> new ReadOnlyStringWrapper(p.getValue().getValue().getData())); 1893 treeTableView.getColumns().add(column); 1894 1895 // show treeTableView 1896 StageLoader sl = new StageLoader(treeTableView); 1897 1898 // expand all collapsed branches 1899 root.setExpanded(true); 1900 for (int i = 0; i < root.getChildren().size(); i++) { 1901 TreeItem<Data> child = root.getChildren().get(i); 1902 child.setExpanded(true); 1903 } 1904 1905 // get all cells and ensure their content is as expected 1906 int cellCount = VirtualFlowTestUtils.getCellCount(treeTableView); 1907 for (int i = 0; i < cellCount; i++) { 1908 // get the TreeTableRow 1909 final TreeTableRow rowCell = (TreeTableRow) VirtualFlowTestUtils.getCell(treeTableView, i); 1910 final TreeItem treeItem = rowCell.getTreeItem(); 1911 if (treeItem == null) continue; 1912 1913 final boolean isBranch = ! treeItem.isLeaf(); 1914 1915 // then check its children 1916 List<Node> children = rowCell.getChildrenUnmodifiable(); 1917 for (int j = 0; j < children.size(); j++) { 1918 final Node child = children.get(j); 1919 1920 assertTrue(child.isVisible()); 1921 assertNotNull(child.getParent()); 1922 assertNotNull(child.getScene()); 1923 1924 if (child.getStyleClass().contains("tree-disclosure-node")) { 1925 // no-op 1926 } 1927 1928 if (child.getStyleClass().contains("tree-table-cell")) { 1929 TreeTableCell cell = (TreeTableCell) child; 1930 assertNotNull(cell.getText()); 1931 assertFalse(cell.getText().isEmpty()); 1932 } 1933 } 1934 } 1935 1936 sl.dispose(); 1937 } 1938 private void addLevel(TreeItem<Data> item, int level, int length) { 1939 for (int i = 0; i < 3; i++) { 1940 StringBuilder builder = new StringBuilder(); 1941 builder.append("Level " + level + " Item " + item); 1942 if (length > 0) { 1943 builder.append(" l"); 1944 for (int j = 0; j < length; j++) { 1945 builder.append("o"); 1946 } 1947 builder.append("ng"); 1948 } 1949 String itemString = builder.toString(); 1950 TreeItem<Data> child = new TreeItem<Data>(new Data(itemString)); 1951 if (level < 3 - 1) { 1952 addLevel(child, level + 1, length); 1953 } 1954 item.getChildren().add(child); 1955 } 1956 } 1957 1958 @Test public void test_rt27180_collapseBranch_childSelected_singleSelection() { 1959 sm.setCellSelectionEnabled(false); 1960 sm.setSelectionMode(SelectionMode.SINGLE); 1961 1962 treeTableView.setRoot(myCompanyRootNode); 1963 myCompanyRootNode.setExpanded(true); 1964 salesDepartment.setExpanded(true); 1965 itSupport.setExpanded(true); 1966 sm.select(2); // ethanWilliams 1967 assertFalse(sm.isSelected(1)); // salesDepartment 1968 assertTrue(sm.isSelected(2)); // ethanWilliams 1969 assertTrue(treeTableView.getFocusModel().isFocused(2)); 1970 assertEquals(1, sm.getSelectedCells().size()); 1971 1972 // now collapse the salesDepartment, selection should 1973 // not jump down to the itSupport people 1974 salesDepartment.setExpanded(false); 1975 assertTrue(sm.getSelectedIndices().toString(), sm.isSelected(1)); // salesDepartment 1976 assertTrue(treeTableView.getFocusModel().isFocused(1)); 1977 assertEquals(1, sm.getSelectedCells().size()); 1978 } 1979 1980 @Test public void test_rt27180_collapseBranch_laterSiblingSelected_singleSelection() { 1981 sm.setCellSelectionEnabled(false); 1982 sm.setSelectionMode(SelectionMode.SINGLE); 1983 1984 treeTableView.setRoot(myCompanyRootNode); 1985 myCompanyRootNode.setExpanded(true); 1986 salesDepartment.setExpanded(true); 1987 itSupport.setExpanded(true); 1988 sm.select(8); // itSupport 1989 assertFalse(sm.isSelected(1)); // salesDepartment 1990 assertTrue(sm.isSelected(8)); // itSupport 1991 assertTrue(treeTableView.getFocusModel().isFocused(8)); 1992 assertEquals(1, sm.getSelectedIndices().size()); 1993 1994 salesDepartment.setExpanded(false); 1995 assertTrue(debug(), sm.isSelected(2)); // itSupport 1996 assertTrue(treeTableView.getFocusModel().isFocused(2)); 1997 assertEquals(1, sm.getSelectedIndices().size()); 1998 } 1999 2000 @Test public void test_rt27180_collapseBranch_laterSiblingAndChildrenSelected() { 2001 sm.setSelectionMode(SelectionMode.MULTIPLE); 2002 sm.setCellSelectionEnabled(false); 2003 2004 treeTableView.setRoot(myCompanyRootNode); 2005 myCompanyRootNode.setExpanded(true); 2006 salesDepartment.setExpanded(true); 2007 itSupport.setExpanded(true); 2008 sm.clearSelection(); 2009 sm.selectIndices(8, 9, 10); // itSupport, and two people 2010 assertFalse(sm.isSelected(1)); // salesDepartment 2011 assertTrue(sm.isSelected(8)); // itSupport 2012 assertTrue(sm.isSelected(9)); // mikeGraham 2013 assertTrue(sm.isSelected(10)); // judyMayer 2014 assertTrue(treeTableView.getFocusModel().isFocused(10)); 2015 assertEquals(debug(), 3, sm.getSelectedIndices().size()); 2016 2017 salesDepartment.setExpanded(false); 2018 assertTrue(debug(), sm.isSelected(2)); // itSupport 2019 assertTrue(sm.isSelected(3)); // mikeGraham 2020 assertTrue(sm.isSelected(4)); // judyMayer 2021 assertTrue(treeTableView.getFocusModel().isFocused(4)); 2022 assertEquals(3, sm.getSelectedIndices().size()); 2023 } 2024 2025 @Test public void test_rt27180_expandBranch_laterSiblingSelected_singleSelection() { 2026 sm.setCellSelectionEnabled(false); 2027 sm.setSelectionMode(SelectionMode.SINGLE); 2028 2029 treeTableView.setRoot(myCompanyRootNode); 2030 myCompanyRootNode.setExpanded(true); 2031 salesDepartment.setExpanded(false); 2032 itSupport.setExpanded(true); 2033 sm.select(2); // itSupport 2034 assertFalse(sm.isSelected(1)); // salesDepartment 2035 assertTrue(sm.isSelected(2)); // itSupport 2036 assertTrue(treeTableView.getFocusModel().isFocused(2)); 2037 assertEquals(1, sm.getSelectedIndices().size()); 2038 2039 salesDepartment.setExpanded(true); 2040 assertTrue(debug(), sm.isSelected(8)); // itSupport 2041 assertTrue(treeTableView.getFocusModel().isFocused(8)); 2042 assertEquals(1, sm.getSelectedIndices().size()); 2043 } 2044 2045 @Test public void test_rt27180_expandBranch_laterSiblingAndChildrenSelected() { 2046 sm.setSelectionMode(SelectionMode.MULTIPLE); 2047 sm.setCellSelectionEnabled(false); 2048 2049 treeTableView.setRoot(myCompanyRootNode); 2050 myCompanyRootNode.setExpanded(true); 2051 salesDepartment.setExpanded(false); 2052 itSupport.setExpanded(true); 2053 sm.clearSelection(); 2054 sm.selectIndices(2,3,4); // itSupport, and two people 2055 assertFalse(sm.isSelected(1)); // salesDepartment 2056 assertTrue(sm.isSelected(2)); // itSupport 2057 assertTrue(sm.isSelected(3)); // mikeGraham 2058 assertTrue(sm.isSelected(4)); // judyMayer 2059 assertTrue(treeTableView.getFocusModel().isFocused(4)); 2060 assertEquals(3, sm.getSelectedIndices().size()); 2061 2062 salesDepartment.setExpanded(true); 2063 assertTrue(debug(), sm.isSelected(8)); // itSupport 2064 assertTrue(sm.isSelected(9)); // mikeGraham 2065 assertTrue(sm.isSelected(10)); // judyMayer 2066 assertTrue(treeTableView.getFocusModel().isFocused(10)); 2067 assertEquals(3, sm.getSelectedIndices().size()); 2068 } 2069 2070 @Test public void test_rt30400() { 2071 // create a treetableview that'll render cells using the check box cell factory 2072 TreeItem<String> rootItem = new TreeItem<>("root"); 2073 final TreeTableView<String> tableView = new TreeTableView<String>(rootItem); 2074 tableView.setMinHeight(100); 2075 tableView.setPrefHeight(100); 2076 2077 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 2078 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 2079 firstNameCol.setCellFactory(CheckBoxTreeTableCell.forTreeTableColumn(param -> new ReadOnlyBooleanWrapper(true))); 2080 tableView.getColumns().add(firstNameCol); 2081 2082 // because only the first row has data, all other rows should be 2083 // empty (and not contain check boxes - we just check the first four here) 2084 VirtualFlowTestUtils.assertRowsNotEmpty(tableView, 0, 1); 2085 VirtualFlowTestUtils.assertCellNotEmpty(VirtualFlowTestUtils.getCell(tableView, 0)); 2086 VirtualFlowTestUtils.assertCellEmpty(VirtualFlowTestUtils.getCell(tableView, 1)); 2087 VirtualFlowTestUtils.assertCellEmpty(VirtualFlowTestUtils.getCell(tableView, 2)); 2088 VirtualFlowTestUtils.assertCellEmpty(VirtualFlowTestUtils.getCell(tableView, 3)); 2089 } 2090 2091 @Ignore("This bug is not yet fixed") 2092 @Test public void test_rt31165() { 2093 installChildren(); 2094 treeTableView.setEditable(true); 2095 2096 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 2097 firstNameCol.setCellValueFactory(param -> new ReadOnlyStringWrapper("TEST")); 2098 firstNameCol.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn()); 2099 firstNameCol.setEditable(true); 2100 2101 treeTableView.getColumns().add(firstNameCol); 2102 2103 IndexedCell cell = VirtualFlowTestUtils.getCell(treeTableView, 1, 0); 2104 assertEquals("TEST", cell.getText()); 2105 assertFalse(cell.isEditing()); 2106 2107 treeTableView.edit(1, firstNameCol); 2108 2109 assertEquals(child1, treeTableView.getEditingCell().getTreeItem()); 2110 assertTrue(cell.isEditing()); 2111 2112 VirtualFlowTestUtils.getVirtualFlow(treeTableView).requestLayout(); 2113 Toolkit.getToolkit().firePulse(); 2114 2115 assertEquals(child1, treeTableView.getEditingCell().getTreeItem()); 2116 assertTrue(cell.isEditing()); 2117 } 2118 2119 @Test public void test_rt31404() { 2120 installChildren(); 2121 2122 TreeTableColumn<String,String> firstNameCol = new TreeTableColumn<>("First Name"); 2123 firstNameCol.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue())); 2124 2125 treeTableView.getColumns().add(firstNameCol); 2126 2127 IndexedCell cell = VirtualFlowTestUtils.getCell(treeTableView, 0, 0); 2128 assertEquals("Root", cell.getText()); 2129 2130 treeTableView.setShowRoot(false); 2131 assertEquals("Child 1", cell.getText()); 2132 } 2133 2134 @Test public void test_rt31471() { 2135 installChildren(); 2136 2137 TreeTableColumn<String,String> firstNameCol = new TreeTableColumn<>("First Name"); 2138 firstNameCol.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue())); 2139 2140 treeTableView.getColumns().add(firstNameCol); 2141 2142 IndexedCell cell = VirtualFlowTestUtils.getCell(treeTableView, 0); 2143 assertEquals("Root", cell.getItem()); 2144 2145 treeTableView.setFixedCellSize(50); 2146 2147 VirtualFlowTestUtils.getVirtualFlow(treeTableView).requestLayout(); 2148 Toolkit.getToolkit().firePulse(); 2149 2150 assertEquals("Root", cell.getItem()); 2151 assertEquals(50, cell.getHeight(), 0.00); 2152 } 2153 2154 @Test public void test_rt30466() { 2155 final Node graphic1 = new Circle(6.75, Color.RED); 2156 final Node graphic2 = new Circle(6.75, Color.GREEN); 2157 2158 installChildren(); 2159 2160 TreeTableColumn<String,String> firstNameCol = new TreeTableColumn<>("First Name"); 2161 firstNameCol.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue())); 2162 2163 treeTableView.getColumns().add(firstNameCol); 2164 2165 TreeTableRow cell = (TreeTableRow) VirtualFlowTestUtils.getCell(treeTableView, 0); 2166 assertEquals("Root", cell.getItem()); 2167 2168 // set the first graphic - which we expect to see as a child of the cell 2169 root.setGraphic(graphic1); 2170 cell = (TreeTableRow) VirtualFlowTestUtils.getCell(treeTableView, 0); 2171 boolean matchGraphic1 = false; 2172 boolean matchGraphic2 = false; 2173 for (Node n : cell.getChildrenUnmodifiable()) { 2174 if (n == graphic1) { 2175 matchGraphic1 = true; 2176 } 2177 if (n == graphic2) { 2178 matchGraphic2 = true; 2179 } 2180 } 2181 assertTrue(matchGraphic1); 2182 assertFalse(matchGraphic2); 2183 2184 // set the second graphic - which we also expect to see - but of course graphic1 should not be a child any longer 2185 root.setGraphic(graphic2); 2186 cell = (TreeTableRow) VirtualFlowTestUtils.getCell(treeTableView, 0); 2187 matchGraphic1 = false; 2188 matchGraphic2 = false; 2189 for (Node n : cell.getChildrenUnmodifiable()) { 2190 if (n == graphic1) { 2191 matchGraphic1 = true; 2192 } 2193 if (n == graphic2) { 2194 matchGraphic2 = true; 2195 } 2196 } 2197 assertFalse(matchGraphic1); 2198 assertTrue(matchGraphic2); 2199 } 2200 2201 private int rt_31200_count = 0; 2202 @Test public void test_rt_31200_tableCell() { 2203 rt_31200_count = 0; 2204 2205 installChildren(); 2206 TreeTableColumn<String,String> firstNameCol = new TreeTableColumn<>("First Name"); 2207 firstNameCol.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue())); 2208 treeTableView.getColumns().add(firstNameCol); 2209 2210 firstNameCol.setCellFactory(new Callback<TreeTableColumn<String, String>, TreeTableCell<String, String>>() { 2211 @Override 2212 public TreeTableCell<String, String> call(TreeTableColumn<String, String> param) { 2213 return new TreeTableCellShim<String, String>() { 2214 ImageView view = new ImageView(); 2215 2216 { 2217 setGraphic(view); 2218 } 2219 2220 ; 2221 2222 @Override 2223 public void updateItem(String item, boolean empty) { 2224 if (getItem() == null ? item == null : getItem().equals(item)) { 2225 rt_31200_count++; 2226 } 2227 super.updateItem(item, empty); 2228 if (item == null || empty) { 2229 view.setImage(null); 2230 setText(null); 2231 } else { 2232 setText(item); 2233 } 2234 } 2235 }; 2236 } 2237 }); 2238 2239 StageLoader sl = new StageLoader(treeTableView); 2240 2241 assertEquals(12, rt_31200_count); 2242 2243 // resize the stage 2244 sl.getStage().setHeight(250); 2245 Toolkit.getToolkit().firePulse(); 2246 sl.getStage().setHeight(50); 2247 Toolkit.getToolkit().firePulse(); 2248 assertEquals(12, rt_31200_count); 2249 2250 sl.dispose(); 2251 } 2252 2253 @Test public void test_rt_31200_tableRow() { 2254 rt_31200_count = 0; 2255 2256 installChildren(); 2257 TreeTableColumn<String,String> firstNameCol = new TreeTableColumn<>("First Name"); 2258 firstNameCol.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue())); 2259 treeTableView.getColumns().add(firstNameCol); 2260 2261 treeTableView.setRowFactory(new Callback<TreeTableView<String>, TreeTableRow<String>>() { 2262 @Override 2263 public TreeTableRow<String> call(TreeTableView<String> param) { 2264 return new TreeTableRowShim<String>() { 2265 ImageView view = new ImageView(); 2266 2267 { 2268 setGraphic(view); 2269 } 2270 2271 ; 2272 2273 @Override 2274 public void updateItem(String item, boolean empty) { 2275 if (getItem() == null ? item == null : getItem().equals(item)) { 2276 rt_31200_count++; 2277 } 2278 super.updateItem(item, empty); 2279 if (item == null || empty) { 2280 view.setImage(null); 2281 setText(null); 2282 } else { 2283 setText(item.toString()); 2284 } 2285 } 2286 }; 2287 } 2288 }); 2289 2290 StageLoader sl = new StageLoader(treeTableView); 2291 2292 assertEquals(21, rt_31200_count); 2293 2294 // resize the stage 2295 sl.getStage().setHeight(250); 2296 Toolkit.getToolkit().firePulse(); 2297 sl.getStage().setHeight(50); 2298 Toolkit.getToolkit().firePulse(); 2299 assertEquals(21, rt_31200_count); 2300 2301 sl.dispose(); 2302 } 2303 2304 @Test public void test_rt_31727() { 2305 installChildren(); 2306 treeTableView.setEditable(true); 2307 2308 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 2309 firstNameCol.setCellValueFactory(param -> new ReadOnlyStringWrapper("TEST")); 2310 firstNameCol.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn()); 2311 firstNameCol.setEditable(true); 2312 2313 treeTableView.getColumns().add(firstNameCol); 2314 2315 treeTableView.setEditable(true); 2316 firstNameCol.setEditable(true); 2317 2318 // do a normal edit 2319 treeTableView.edit(0, firstNameCol); 2320 TreeTablePosition editingCell = treeTableView.getEditingCell(); 2321 assertNotNull(editingCell); 2322 assertEquals(0, editingCell.getRow()); 2323 assertEquals(0, editingCell.getColumn()); 2324 assertEquals(firstNameCol, editingCell.getTableColumn()); 2325 assertEquals(treeTableView, editingCell.getTreeTableView()); 2326 2327 // cancel editing 2328 treeTableView.edit(-1, null); 2329 editingCell = treeTableView.getEditingCell(); 2330 assertNull(editingCell); 2331 } 2332 2333 @Test public void test_rt_21517() { 2334 installChildren(); 2335 2336 // final TableSelectionModel sm = t.getSelectionModel(); 2337 TreeTableColumn<String, String> col = new TreeTableColumn<String, String>("column"); 2338 col.setSortType(ASCENDING); 2339 col.setCellValueFactory(param -> new ReadOnlyObjectWrapper<String>(param.getValue().getValue())); 2340 treeTableView.getColumns().add(col); 2341 2342 // test pre-conditions 2343 assertEquals(0, sm.getSelectedCells().size()); 2344 assertEquals(0, sm.getSelectedItems().size()); 2345 assertEquals(0, sm.getSelectedIndices().size()); 2346 2347 // select the 4th row (that is, the third child of the root) 2348 sm.select(3); 2349 assertTrue(sm.isSelected(3)); 2350 assertEquals(3, sm.getSelectedIndex()); 2351 assertEquals(1, sm.getSelectedIndices().size()); 2352 assertTrue(sm.getSelectedIndices().contains(3)); 2353 assertEquals(child3, sm.getSelectedItem()); 2354 assertEquals(1, sm.getSelectedItems().size()); 2355 assertTrue(sm.getSelectedItems().contains(child3)); 2356 2357 // we also want to test visually 2358 TreeTableRow rootRow = (TreeTableRow) VirtualFlowTestUtils.getCell(treeTableView, 0); 2359 assertFalse(rootRow.isSelected()); 2360 TreeTableRow child3Row = (TreeTableRow) VirtualFlowTestUtils.getCell(treeTableView, 3); 2361 assertTrue(child3Row.isSelected()); 2362 2363 // sort tableview by firstname column in ascending (default) order 2364 // (so aaa continues to come first) 2365 treeTableView.getSortOrder().add(col); 2366 2367 // nothing should have changed 2368 assertTrue(sm.isSelected(3)); 2369 assertEquals(3, sm.getSelectedIndex()); 2370 assertEquals(1, sm.getSelectedIndices().size()); 2371 assertTrue(sm.getSelectedIndices().contains(3)); 2372 assertEquals(child3, sm.getSelectedItem()); 2373 assertEquals(1, sm.getSelectedItems().size()); 2374 assertTrue(sm.getSelectedItems().contains(child3)); 2375 rootRow = (TreeTableRow) VirtualFlowTestUtils.getCell(treeTableView, 0); 2376 assertFalse(rootRow.isSelected()); 2377 child3Row = (TreeTableRow) VirtualFlowTestUtils.getCell(treeTableView, 3); 2378 assertTrue(child3Row.isSelected()); 2379 2380 // continue to sort tableview by firstname column, but now in descending 2381 // order, (so ccc to come first) 2382 col.setSortType(TreeTableColumn.SortType.DESCENDING); 2383 2384 // now test to ensure that CCC is still the only selected item, but now 2385 // located in index 1 (as the first child of the root) 2386 assertTrue(debug(), sm.isSelected(1)); 2387 assertEquals(1, sm.getSelectedIndex()); 2388 assertEquals(1, sm.getSelectedIndices().size()); 2389 assertTrue(sm.getSelectedIndices().contains(1)); 2390 assertEquals(child3, sm.getSelectedItem()); 2391 assertEquals(1, sm.getSelectedItems().size()); 2392 assertTrue(sm.getSelectedItems().contains(child3)); 2393 2394 // we also want to test visually 2395 rootRow = (TreeTableRow) VirtualFlowTestUtils.getCell(treeTableView, 0); 2396 assertFalse(rootRow.isSelected()); 2397 child3Row = (TreeTableRow) VirtualFlowTestUtils.getCell(treeTableView, 1); 2398 assertTrue(child3Row.isSelected()); 2399 } 2400 2401 @Test public void test_rt_30484_treeTableCell() { 2402 installChildren(); 2403 2404 TreeTableColumn<String, String> col = new TreeTableColumn<String, String>("column"); 2405 col.setSortType(ASCENDING); 2406 col.setCellValueFactory(param -> new ReadOnlyObjectWrapper<String>(param.getValue().getValue())); 2407 treeTableView.getColumns().add(col); 2408 2409 col.setCellFactory(new Callback<TreeTableColumn<String, String>, TreeTableCell<String, String>>() { 2410 @Override 2411 public TreeTableCell<String, String> call(TreeTableColumn<String, String> param) { 2412 return new TreeTableCellShim<String, String>() { 2413 Rectangle graphic = new Rectangle(10, 10, Color.RED); 2414 { setGraphic(graphic); }; 2415 2416 @Override public void updateItem(String item, boolean empty) { 2417 super.updateItem(item, empty); 2418 if (item == null || empty) { 2419 graphic.setVisible(false); 2420 setText(null); 2421 } else { 2422 graphic.setVisible(true); 2423 setText(item); 2424 } 2425 } 2426 }; 2427 } 2428 }); 2429 2430 // First four rows have content, so the graphic should show. 2431 // All other rows have no content, so graphic should not show. 2432 2433 VirtualFlowTestUtils.assertGraphicIsVisible(treeTableView, 0, 0); 2434 VirtualFlowTestUtils.assertGraphicIsVisible(treeTableView, 1, 0); 2435 VirtualFlowTestUtils.assertGraphicIsVisible(treeTableView, 2, 0); 2436 VirtualFlowTestUtils.assertGraphicIsVisible(treeTableView, 3, 0); 2437 VirtualFlowTestUtils.assertGraphicIsNotVisible(treeTableView, 4, 0); 2438 VirtualFlowTestUtils.assertGraphicIsNotVisible(treeTableView, 5, 0); 2439 } 2440 2441 @Test public void test_rt_30484_treeTableRow() { 2442 installChildren(); 2443 2444 TreeTableColumn<String, String> col = new TreeTableColumn<String, String>("column"); 2445 col.setSortType(ASCENDING); 2446 col.setCellValueFactory(param -> new ReadOnlyObjectWrapper<String>(param.getValue().getValue())); 2447 treeTableView.getColumns().add(col); 2448 2449 treeTableView.setRowFactory(new Callback<TreeTableView<String>, TreeTableRow<String>>() { 2450 @Override public TreeTableRow<String> call(TreeTableView<String> param) { 2451 return new TreeTableRowShim<String>() { 2452 Rectangle graphic = new Rectangle(10, 10, Color.RED); 2453 { setGraphic(graphic); }; 2454 2455 @Override public void updateItem(String item, boolean empty) { 2456 super.updateItem(item, empty); 2457 if (item == null || empty) { 2458 graphic.setVisible(false); 2459 setText(null); 2460 } else { 2461 graphic.setVisible(true); 2462 setText(item.toString()); 2463 } 2464 } 2465 }; 2466 } 2467 }); 2468 2469 // First two rows have content, so the graphic should show. 2470 // All other rows have no content, so graphic should not show. 2471 2472 VirtualFlowTestUtils.assertGraphicIsVisible(treeTableView, 0); 2473 VirtualFlowTestUtils.assertGraphicIsVisible(treeTableView, 1); 2474 VirtualFlowTestUtils.assertGraphicIsVisible(treeTableView, 2); 2475 VirtualFlowTestUtils.assertGraphicIsVisible(treeTableView, 3); 2476 VirtualFlowTestUtils.assertGraphicIsNotVisible(treeTableView, 4); 2477 VirtualFlowTestUtils.assertGraphicIsNotVisible(treeTableView, 5); 2478 } 2479 2480 private int rt_31015_count = 0; 2481 @Test public void test_rt_31015() { 2482 installChildren(); 2483 root.getChildren().clear(); 2484 treeTableView.setEditable(true); 2485 2486 TreeTableColumn<String, String> col = new TreeTableColumn<String, String>("column"); 2487 col.setCellValueFactory(param -> new ReadOnlyObjectWrapper<String>(param.getValue().getValue())); 2488 treeTableView.getColumns().add(col); 2489 2490 //Set cell factory for cells that allow editing 2491 Callback<TreeTableColumn<String,String>, TreeTableCell<String, String>> cellFactory = new Callback<TreeTableColumn<String,String>, TreeTableCell<String, String>>() { 2492 public TreeTableCell<String, String> call(TreeTableColumn<String, String> p) { 2493 return new TreeTableCell<String, String>() { 2494 @Override public void cancelEdit() { 2495 super.cancelEdit(); 2496 rt_31015_count++; 2497 } 2498 }; 2499 } 2500 }; 2501 col.setCellFactory(cellFactory); 2502 2503 StageLoader sl = new StageLoader(treeTableView); 2504 2505 assertEquals(0, rt_31015_count); 2506 2507 treeTableView.edit(0, col); 2508 assertEquals(0, rt_31015_count); 2509 2510 treeTableView.edit(-1, null); 2511 assertEquals(1, rt_31015_count); 2512 2513 sl.dispose(); 2514 } 2515 2516 @Test public void test_rt_30688() { 2517 installChildren(); 2518 root.getChildren().clear(); 2519 treeTableView.setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY); 2520 2521 TreeTableColumn<String, String> col = new TreeTableColumn<>("column"); 2522 col.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().getValue())); 2523 treeTableView.getColumns().add(col); 2524 2525 StageLoader sl = new StageLoader(treeTableView); 2526 2527 assertEquals(TreeTableViewShim.get_contentWidth(treeTableView), 2528 TableColumnBaseShim.getWidth(col), 0.0); 2529 2530 sl.dispose(); 2531 } 2532 2533 private int rt_29650_start_count = 0; 2534 private int rt_29650_commit_count = 0; 2535 private int rt_29650_cancel_count = 0; 2536 @Test public void test_rt_29650() { 2537 installChildren(); 2538 treeTableView.setEditable(true); 2539 2540 TreeTableColumn<String, String> col = new TreeTableColumn<>("column"); 2541 Callback<TreeTableColumn<String, String>, TreeTableCell<String, String>> factory = TextFieldTreeTableCell.forTreeTableColumn(); 2542 col.setCellFactory(factory); 2543 col.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().getValue())); 2544 treeTableView.getColumns().add(col); 2545 2546 col.setOnEditStart(t -> { 2547 rt_29650_start_count++; 2548 }); 2549 col.setOnEditCommit(t -> { 2550 rt_29650_commit_count++; 2551 }); 2552 col.setOnEditCancel(t -> { 2553 rt_29650_cancel_count++; 2554 }); 2555 2556 StageLoader sl = new StageLoader(treeTableView); 2557 2558 treeTableView.edit(0, col); 2559 2560 Toolkit.getToolkit().firePulse(); 2561 2562 TreeTableCell rootCell = (TreeTableCell) VirtualFlowTestUtils.getCell(treeTableView, 0, 0); 2563 TextField textField = (TextField) rootCell.getGraphic(); 2564 textField.setText("Testing!"); 2565 KeyEventFirer keyboard = new KeyEventFirer(textField); 2566 keyboard.doKeyPress(KeyCode.ENTER); 2567 2568 // TODO should the following assert be enabled? 2569 // assertEquals("Testing!", listView.getItems().get(0)); 2570 assertEquals(1, rt_29650_start_count); 2571 assertEquals(1, rt_29650_commit_count); 2572 assertEquals(0, rt_29650_cancel_count); 2573 2574 sl.dispose(); 2575 } 2576 2577 private int rt_29849_start_count = 0; 2578 @Test public void test_rt_29849() { 2579 installChildren(); 2580 treeTableView.setEditable(true); 2581 2582 TreeTableColumn<String, String> col = new TreeTableColumn<>("column"); 2583 col.setEditable(true); 2584 col.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().getValue())); 2585 treeTableView.getColumns().add(col); 2586 2587 col.setOnEditStart(t -> { 2588 rt_29849_start_count++; 2589 }); 2590 2591 // load the table so the default cells are created 2592 StageLoader sl = new StageLoader(treeTableView); 2593 2594 // now replace the cell factory 2595 Callback<TreeTableColumn<String, String>, TreeTableCell<String, String>> factory = TextFieldTreeTableCell.forTreeTableColumn(); 2596 col.setCellFactory(factory); 2597 2598 Toolkit.getToolkit().firePulse(); 2599 2600 // now start an edit and count the start edit events - it should be just 1 2601 treeTableView.edit(0, col); 2602 assertEquals(1, rt_29849_start_count); 2603 2604 sl.dispose(); 2605 } 2606 2607 @Test public void test_rt_34327() { 2608 // by default the comparator is null. 2609 // NOTE: this method (prior to the fix as part of RT-34327) would have 2610 // returned Comparator<String>, but after the fix it correctly returns 2611 // a Comparator<TreeItem<String>> 2612 Comparator nonGenericComparator = treeTableView.getComparator(); 2613 Comparator<TreeItem<String>> genericComparator = treeTableView.getComparator(); 2614 assertNull(nonGenericComparator); 2615 assertNull(genericComparator); 2616 2617 // add in a column and some data 2618 TreeTableColumn<String, String> col = new TreeTableColumn<>("column"); 2619 col.setEditable(true); 2620 col.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().getValue())); 2621 treeTableView.getColumns().add(col); 2622 2623 installChildren(); 2624 2625 // sort by that column 2626 treeTableView.getSortOrder().add(col); 2627 2628 // get the new comparator, which should no longer be null 2629 nonGenericComparator = treeTableView.getComparator(); 2630 genericComparator = treeTableView.getComparator(); 2631 assertNotNull(nonGenericComparator); 2632 assertNotNull(genericComparator); 2633 2634 // now, as noted above, previously we would use the Comparator to compare 2635 // two String instances, which would fail at runtime as the Comparator 2636 // was actually expecting to compare two TreeItem<String>, but the API 2637 // was failing us. 2638 try { 2639 nonGenericComparator.compare("abc", "def"); 2640 fail("This should not work!"); 2641 } catch (ClassCastException e) { 2642 // if we get the exception, we're happy 2643 } 2644 2645 try { 2646 Object string1 = "abc"; 2647 Object string2 = "def"; 2648 genericComparator.compare((TreeItem<String>)string1, (TreeItem<String>)string2); 2649 fail("This should not work!"); 2650 } catch (ClassCastException e) { 2651 // if we get the exception, we're happy 2652 } 2653 } 2654 2655 @Test public void test_rt26718() { 2656 treeTableView.setRoot(new TreeItem("Root")); 2657 treeTableView.getRoot().setExpanded(true); 2658 2659 for (int i = 0; i < 4; i++) { 2660 TreeItem parent = new TreeItem("item - " + i); 2661 treeTableView.getRoot().getChildren().add(parent); 2662 2663 for (int j = 0; j < 4; j++) { 2664 TreeItem child = new TreeItem("item - " + i + " " + j); 2665 parent.getChildren().add(child); 2666 } 2667 } 2668 2669 treeTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 2670 2671 final TreeItem item0 = treeTableView.getTreeItem(1); 2672 final TreeItem item1 = treeTableView.getTreeItem(2); 2673 2674 assertEquals("item - 0", item0.getValue()); 2675 assertEquals("item - 1", item1.getValue()); 2676 2677 item0.setExpanded(true); 2678 item1.setExpanded(true); 2679 Toolkit.getToolkit().firePulse(); 2680 2681 treeTableView.getSelectionModel().selectRange(0, 8); 2682 assertEquals(8, treeTableView.getSelectionModel().getSelectedIndices().size()); 2683 assertEquals(7, treeTableView.getSelectionModel().getSelectedIndex()); 2684 assertEquals(7, treeTableView.getFocusModel().getFocusedIndex()); 2685 2686 // collapse item0 - but because the selected and focused indices are 2687 // not children of item 0, they should remain where they are (but of 2688 // course be shifted up). The bug was that focus was moving up to item0, 2689 // which makes no sense 2690 item0.setExpanded(false); 2691 Toolkit.getToolkit().firePulse(); 2692 assertEquals(3, treeTableView.getSelectionModel().getSelectedIndex()); 2693 assertEquals(3, treeTableView.getFocusModel().getFocusedIndex()); 2694 } 2695 2696 // @Ignore("Test started intermittently failing, most probably due to RT-36855 changeset") 2697 @Test public void test_rt_34493() { 2698 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 2699 new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")) 2700 ); 2701 2702 TreeTableView<Person> table = new TreeTableView<>(); 2703 2704 TreeItem<Person> root = new TreeItem<Person>(new Person("Root", null, null)); 2705 root.setExpanded(true); 2706 table.setRoot(root); 2707 table.setShowRoot(false); 2708 root.getChildren().setAll(persons); 2709 2710 TreeTableColumn first = new TreeTableColumn("First Name"); 2711 first.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 2712 2713 TreeTableColumn last = new TreeTableColumn("Last Name"); 2714 last.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 2715 2716 TreeTableColumn email = new TreeTableColumn("Email"); 2717 email.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("email")); 2718 2719 table.getColumns().addAll(first, last, email); 2720 2721 // load the table 2722 StageLoader sl = new StageLoader(table); 2723 2724 // resize the last column 2725 last.impl_setWidth(400); 2726 assertEquals(400, last.getWidth(), 0.0); 2727 2728 // hide the first column 2729 table.getColumns().remove(first); 2730 Toolkit.getToolkit().firePulse(); 2731 2732 // the last column should still be 400px, not the default width or any 2733 // other value (based on the width of the content in that column) 2734 assertEquals(400, last.getWidth(), 0.0); 2735 2736 sl.dispose(); 2737 } 2738 2739 @Test public void test_rt26721_collapseParent_firstRootChild() { 2740 TreeTableView<String> table = new TreeTableView<>(); 2741 table.setRoot(new TreeItem("Root")); 2742 table.getRoot().setExpanded(true); 2743 2744 for (int i = 0; i < 4; i++) { 2745 TreeItem parent = new TreeItem("item - " + i); 2746 table.getRoot().getChildren().add(parent); 2747 2748 for (int j = 0; j < 4; j++) { 2749 TreeItem child = new TreeItem("item - " + i + " " + j); 2750 parent.getChildren().add(child); 2751 } 2752 } 2753 2754 table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 2755 2756 final TreeItem<String> item0 = table.getTreeItem(1); 2757 final TreeItem<String> item0child0 = item0.getChildren().get(0); 2758 final TreeItem<String> item1 = table.getTreeItem(2); 2759 2760 assertEquals("item - 0", item0.getValue()); 2761 assertEquals("item - 1", item1.getValue()); 2762 2763 item0.setExpanded(true); 2764 item1.setExpanded(true); 2765 Toolkit.getToolkit().firePulse(); 2766 2767 // select the first child of item0 2768 table.getSelectionModel().select(item0child0); 2769 2770 assertEquals(item0child0, table.getSelectionModel().getSelectedItem()); 2771 assertEquals(item0child0, table.getFocusModel().getFocusedItem()); 2772 2773 // collapse item0 - we expect the selection / focus to move up to item0 2774 item0.setExpanded(false); 2775 Toolkit.getToolkit().firePulse(); 2776 assertEquals(item0, table.getSelectionModel().getSelectedItem()); 2777 assertEquals(item0, table.getFocusModel().getFocusedItem()); 2778 } 2779 2780 @Test public void test_rt26721_collapseParent_lastRootChild() { 2781 TreeTableView<String> table = new TreeTableView<>(); 2782 table.setRoot(new TreeItem("Root")); 2783 table.getRoot().setExpanded(true); 2784 2785 for (int i = 0; i < 4; i++) { 2786 TreeItem parent = new TreeItem("item - " + i); 2787 table.getRoot().getChildren().add(parent); 2788 2789 for (int j = 0; j < 4; j++) { 2790 TreeItem child = new TreeItem("item - " + i + " " + j); 2791 parent.getChildren().add(child); 2792 } 2793 } 2794 2795 table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 2796 2797 final TreeItem<String> item3 = table.getTreeItem(4); 2798 final TreeItem<String> item3child0 = item3.getChildren().get(0); 2799 2800 assertEquals("item - 3", item3.getValue()); 2801 assertEquals("item - 3 0", item3child0.getValue()); 2802 2803 item3.setExpanded(true); 2804 Toolkit.getToolkit().firePulse(); 2805 2806 // select the first child of item0 2807 table.getSelectionModel().select(item3child0); 2808 2809 assertEquals(item3child0, table.getSelectionModel().getSelectedItem()); 2810 assertEquals(item3child0, table.getFocusModel().getFocusedItem()); 2811 2812 // collapse item3 - we expect the selection / focus to move up to item3 2813 item3.setExpanded(false); 2814 Toolkit.getToolkit().firePulse(); 2815 assertEquals(item3, table.getSelectionModel().getSelectedItem()); 2816 assertEquals(item3, table.getFocusModel().getFocusedItem()); 2817 } 2818 2819 @Test public void test_rt26721_collapseGrandParent() { 2820 TreeTableView<String> table = new TreeTableView<>(); 2821 table.setRoot(new TreeItem("Root")); 2822 table.getRoot().setExpanded(true); 2823 2824 for (int i = 0; i < 4; i++) { 2825 TreeItem parent = new TreeItem("item - " + i); 2826 table.getRoot().getChildren().add(parent); 2827 2828 for (int j = 0; j < 4; j++) { 2829 TreeItem child = new TreeItem("item - " + i + " " + j); 2830 parent.getChildren().add(child); 2831 } 2832 } 2833 2834 table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 2835 2836 final TreeItem<String> item0 = table.getTreeItem(1); 2837 final TreeItem<String> item0child0 = item0.getChildren().get(0); 2838 final TreeItem<String> item1 = table.getTreeItem(2); 2839 2840 assertEquals("item - 0", item0.getValue()); 2841 assertEquals("item - 1", item1.getValue()); 2842 2843 item0.setExpanded(true); 2844 item1.setExpanded(true); 2845 Toolkit.getToolkit().firePulse(); 2846 2847 // select the first child of item0 2848 table.getSelectionModel().select(item0child0); 2849 2850 assertEquals(item0child0, table.getSelectionModel().getSelectedItem()); 2851 assertEquals(item0child0, table.getFocusModel().getFocusedItem()); 2852 2853 // collapse root - we expect the selection / focus to move up to root 2854 table.getRoot().setExpanded(false); 2855 Toolkit.getToolkit().firePulse(); 2856 assertEquals(table.getRoot(), table.getSelectionModel().getSelectedItem()); 2857 assertEquals(table.getRoot(), table.getFocusModel().getFocusedItem()); 2858 } 2859 2860 @Test public void test_rt_34685_directEditCall_cellSelectionMode() { 2861 test_rt_34685_commitCount = 0; 2862 test_rt_34685(false, true); 2863 } 2864 2865 @Test public void test_rt_34685_directEditCall_rowSelectionMode() { 2866 test_rt_34685_commitCount = 0; 2867 test_rt_34685(false, false); 2868 } 2869 2870 @Test public void test_rt_34685_mouseDoubleClick_cellSelectionMode() { 2871 test_rt_34685_commitCount = 0; 2872 test_rt_34685(true, true); 2873 } 2874 2875 @Test public void test_rt_34685_mouseDoubleClick_rowSelectionMode() { 2876 test_rt_34685_commitCount = 0; 2877 test_rt_34685(true, false); 2878 } 2879 2880 private int test_rt_34685_commitCount = 0; 2881 private void test_rt_34685(boolean useMouseToInitiateEdit, boolean cellSelectionModeEnabled) { 2882 assertEquals(0, test_rt_34685_commitCount); 2883 2884 Person person1; 2885 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 2886 new TreeItem<>(person1 = new Person("John", "Smith", "john.smith@example.com")) 2887 ); 2888 2889 TreeTableView<Person> table = new TreeTableView<>(); 2890 table.getSelectionModel().setCellSelectionEnabled(cellSelectionModeEnabled); 2891 table.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); 2892 table.setEditable(true); 2893 2894 TreeItem<Person> root = new TreeItem<Person>(new Person("Root", null, null)); 2895 root.setExpanded(true); 2896 table.setRoot(root); 2897 table.setShowRoot(false); 2898 root.getChildren().setAll(persons); 2899 2900 TreeTableColumn first = new TreeTableColumn("First Name"); 2901 first.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 2902 first.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn()); 2903 2904 EventHandler<TreeTableColumn.CellEditEvent<Person, String>> onEditCommit = first.getOnEditCommit(); 2905 first.setOnEditCommit(new EventHandler<TreeTableColumn.CellEditEvent<Person, String>>() { 2906 @Override public void handle(TreeTableColumn.CellEditEvent<Person, String> event) { 2907 test_rt_34685_commitCount++; 2908 onEditCommit.handle(event); 2909 } 2910 }); 2911 2912 table.getColumns().addAll(first); 2913 2914 // get the cell at (0,0) - we're hiding the root row 2915 VirtualFlowTestUtils.BLOCK_STAGE_LOADER_DISPOSE = true; 2916 TreeTableCell cell = (TreeTableCell) VirtualFlowTestUtils.getCell(table, 0, 0); 2917 VirtualFlowTestUtils.BLOCK_STAGE_LOADER_DISPOSE = false; 2918 assertTrue(cell.getSkin() instanceof TreeTableCellSkin); 2919 assertNull(cell.getGraphic()); 2920 assertEquals("John", cell.getText()); 2921 assertEquals("John", person1.getFirstName()); 2922 2923 // set the table to be editing the first cell at 0,0 2924 if (useMouseToInitiateEdit) { 2925 MouseEventFirer mouse = new MouseEventFirer(cell); 2926 mouse.fireMousePressAndRelease(2, 10, 10); // click 10 pixels in and 10 pixels down 2927 mouse.dispose(); 2928 } else { 2929 table.edit(0,first); 2930 } 2931 2932 Toolkit.getToolkit().firePulse(); 2933 assertNotNull(cell.getGraphic()); 2934 assertTrue(cell.getGraphic() instanceof TextField); 2935 2936 TextField textField = (TextField) cell.getGraphic(); 2937 assertEquals("John", textField.getText()); 2938 2939 textField.setText("Andrew"); 2940 textField.requestFocus(); 2941 Toolkit.getToolkit().firePulse(); 2942 2943 KeyEventFirer keyboard = new KeyEventFirer(textField); 2944 keyboard.doKeyPress(KeyCode.ENTER); 2945 2946 VirtualFlowTestUtils.getVirtualFlow(table).requestLayout(); 2947 Toolkit.getToolkit().firePulse(); 2948 2949 VirtualFlowTestUtils.assertTableCellTextEquals(table, 0, 0, "Andrew"); 2950 assertEquals("Andrew", cell.getText()); 2951 assertEquals("Andrew", person1.getFirstName()); 2952 assertEquals(1, test_rt_34685_commitCount); 2953 } 2954 2955 @Test public void test_rt34694() { 2956 TreeItem treeNode = new TreeItem("Controls"); 2957 treeNode.getChildren().addAll( 2958 new TreeItem("Button"), 2959 new TreeItem("ButtonBar"), 2960 new TreeItem("LinkBar"), 2961 new TreeItem("LinkButton"), 2962 new TreeItem("PopUpButton"), 2963 new TreeItem("ToggleButtonBar") 2964 ); 2965 2966 final TreeTableView<String> table = new TreeTableView<>(); 2967 table.setRoot(treeNode); 2968 treeNode.setExpanded(true); 2969 2970 table.getSelectionModel().select(0); 2971 assertTrue(table.getSelectionModel().isSelected(0)); 2972 assertTrue(table.getFocusModel().isFocused(0)); 2973 2974 treeNode.getChildren().clear(); 2975 treeNode.getChildren().addAll( 2976 new TreeItem("Button1"), 2977 new TreeItem("ButtonBar1"), 2978 new TreeItem("LinkBar1"), 2979 new TreeItem("LinkButton1"), 2980 new TreeItem("PopUpButton1"), 2981 new TreeItem("ToggleButtonBar1") 2982 ); 2983 Toolkit.getToolkit().firePulse(); 2984 2985 assertTrue(table.getSelectionModel().isSelected(0)); 2986 assertTrue(table.getFocusModel().isFocused(0)); 2987 } 2988 2989 private int test_rt_35213_eventCount = 0; 2990 @Test public void test_rt35213() { 2991 final TreeTableView<String> view = new TreeTableView<>(); 2992 2993 TreeItem<String> root = new TreeItem<>("Boss"); 2994 view.setRoot(root); 2995 2996 TreeItem<String> group1 = new TreeItem<>("Group 1"); 2997 TreeItem<String> group2 = new TreeItem<>("Group 2"); 2998 TreeItem<String> group3 = new TreeItem<>("Group 3"); 2999 3000 root.getChildren().addAll(group1, group2, group3); 3001 3002 TreeItem<String> employee1 = new TreeItem<>("Employee 1"); 3003 TreeItem<String> employee2 = new TreeItem<>("Employee 2"); 3004 3005 group2.getChildren().addAll(employee1, employee2); 3006 3007 TreeTableColumn<String, String> nameColumn = new TreeTableColumn<>("Name"); 3008 nameColumn.setCellValueFactory(new TreeItemPropertyValueFactory<String, String>("name")); 3009 view.getColumns().add(nameColumn); 3010 3011 view.expandedItemCountProperty().addListener((observableValue, oldCount, newCount) -> { 3012 3013 // DEBUG OUTPUT 3014 // System.out.println("new expanded item count: " + newCount.intValue()); 3015 // for (int i = 0; i < newCount.intValue(); i++) { 3016 // TreeItem<String> item = view.getTreeItem(i); 3017 // String text = item.getValue(); 3018 // System.out.println("person found at index " + i + " is " + text); 3019 // } 3020 // System.out.println("------------------------------------------"); 3021 3022 if (test_rt_35213_eventCount == 0) { 3023 assertEquals(4, newCount); 3024 assertEquals("Boss", view.getTreeItem(0).getValue()); 3025 assertEquals("Group 1", view.getTreeItem(1).getValue()); 3026 assertEquals("Group 2", view.getTreeItem(2).getValue()); 3027 assertEquals("Group 3", view.getTreeItem(3).getValue()); 3028 } else if (test_rt_35213_eventCount == 1) { 3029 assertEquals(6, newCount); 3030 assertEquals("Boss", view.getTreeItem(0).getValue()); 3031 assertEquals("Group 1", view.getTreeItem(1).getValue()); 3032 assertEquals("Group 2", view.getTreeItem(2).getValue()); 3033 assertEquals("Employee 1", view.getTreeItem(3).getValue()); 3034 assertEquals("Employee 2", view.getTreeItem(4).getValue()); 3035 assertEquals("Group 3", view.getTreeItem(5).getValue()); 3036 } else if (test_rt_35213_eventCount == 2) { 3037 assertEquals(4, newCount); 3038 assertEquals("Boss", view.getTreeItem(0).getValue()); 3039 assertEquals("Group 1", view.getTreeItem(1).getValue()); 3040 assertEquals("Group 2", view.getTreeItem(2).getValue()); 3041 assertEquals("Group 3", view.getTreeItem(3).getValue()); 3042 } 3043 3044 test_rt_35213_eventCount++; 3045 }); 3046 3047 StageLoader sl = new StageLoader(view); 3048 3049 root.setExpanded(true); 3050 Toolkit.getToolkit().firePulse(); 3051 3052 group2.setExpanded(true); 3053 Toolkit.getToolkit().firePulse(); 3054 3055 group2.setExpanded(false); 3056 Toolkit.getToolkit().firePulse(); 3057 3058 sl.dispose(); 3059 } 3060 3061 @Test public void test_rt23245_itemIsInTree() { 3062 final TreeTableView<String> view = new TreeTableView<String>(); 3063 final List<TreeItem<String>> items = new ArrayList<>(); 3064 for (int i = 0; i < 10; i++) { 3065 final TreeItem<String> item = new TreeItem<String>("Item" + i); 3066 item.setExpanded(true); 3067 items.add(item); 3068 } 3069 3070 // link the items up so that the next item is the child of the current item 3071 for (int i = 0; i < 9; i++) { 3072 items.get(i).getChildren().add(items.get(i + 1)); 3073 } 3074 3075 view.setRoot(items.get(0)); 3076 3077 for (int i = 0; i < 10; i++) { 3078 // we expect the level of the tree item at the ith position to be 3079 // 0, as every iteration we are setting the ith item as the root. 3080 assertEquals(0, view.getTreeItemLevel(items.get(i))); 3081 3082 // whilst we are testing, we should also ensure that the ith item 3083 // is indeed the root item, and that the ith item is indeed the item 3084 // at the 0th position 3085 assertEquals(items.get(i), view.getRoot()); 3086 assertEquals(items.get(i), view.getTreeItem(0)); 3087 3088 // shuffle the next item into the root position (keeping its parent 3089 // chain intact - which is what exposes this issue in the first place). 3090 if (i < 9) { 3091 view.setRoot(items.get(i + 1)); 3092 } 3093 } 3094 } 3095 3096 @Test public void test_rt23245_itemIsNotInTree_noRootNode() { 3097 final TreeView<String> view = new TreeView<String>(); 3098 final List<TreeItem<String>> items = new ArrayList<>(); 3099 for (int i = 0; i < 10; i++) { 3100 final TreeItem<String> item = new TreeItem<String>("Item" + i); 3101 item.setExpanded(true); 3102 items.add(item); 3103 } 3104 3105 // link the items up so that the next item is the child of the current item 3106 for (int i = 0; i < 9; i++) { 3107 items.get(i).getChildren().add(items.get(i + 1)); 3108 } 3109 3110 for (int i = 0; i < 10; i++) { 3111 // because we have no root (and we are not changing the root like 3112 // the previous test), we expect the tree item level of the item 3113 // in the ith position to be i. 3114 assertEquals(i, view.getTreeItemLevel(items.get(i))); 3115 3116 // all items requested from the TreeView should be null, as the 3117 // TreeView does not have a root item 3118 assertNull(view.getTreeItem(i)); 3119 } 3120 } 3121 3122 @Test public void test_rt23245_itemIsNotInTree_withUnrelatedRootNode() { 3123 final TreeView<String> view = new TreeView<String>(); 3124 final List<TreeItem<String>> items = new ArrayList<>(); 3125 for (int i = 0; i < 10; i++) { 3126 final TreeItem<String> item = new TreeItem<String>("Item" + i); 3127 item.setExpanded(true); 3128 items.add(item); 3129 } 3130 3131 // link the items up so that the next item is the child of the current item 3132 for (int i = 0; i < 9; i++) { 3133 items.get(i).getChildren().add(items.get(i + 1)); 3134 } 3135 3136 view.setRoot(new TreeItem("Unrelated root node")); 3137 3138 for (int i = 0; i < 10; i++) { 3139 // because we have no root (and we are not changing the root like 3140 // the previous test), we expect the tree item level of the item 3141 // in the ith position to be i. 3142 assertEquals(i, view.getTreeItemLevel(items.get(i))); 3143 3144 // all items requested from the TreeView should be null except for 3145 // the root node 3146 assertNull(view.getTreeItem(i + 1)); 3147 } 3148 } 3149 3150 @Test public void test_rt35039_setRoot() { 3151 TreeItem aabbaa = new TreeItem("aabbaa"); 3152 TreeItem bbc = new TreeItem("bbc"); 3153 3154 TreeItem<String> root = new TreeItem<>("Root"); 3155 root.setExpanded(true); 3156 root.getChildren().setAll(aabbaa, bbc); 3157 3158 final TreeTableView<String> treeView = new TreeTableView<>(); 3159 treeView.setRoot(root); 3160 3161 StageLoader sl = new StageLoader(treeView); 3162 3163 // Selection starts in row -1 3164 assertNull(treeView.getSelectionModel().getSelectedItem()); 3165 3166 // select "bbc" and ensure everything is set to that 3167 treeView.getSelectionModel().select(2); 3168 assertEquals("bbc", treeView.getSelectionModel().getSelectedItem().getValue()); 3169 3170 // change the items list - but retain the same content. We expect 3171 // that "bbc" remains selected as it is still in the list 3172 treeView.setRoot(root); 3173 assertEquals("bbc", treeView.getSelectionModel().getSelectedItem().getValue()); 3174 3175 sl.dispose(); 3176 } 3177 3178 @Test public void test_rt35039_resetRootChildren() { 3179 TreeItem aabbaa = new TreeItem("aabbaa"); 3180 TreeItem bbc = new TreeItem("bbc"); 3181 3182 TreeItem<String> root = new TreeItem<>("Root"); 3183 root.setExpanded(true); 3184 root.getChildren().setAll(aabbaa, bbc); 3185 3186 final TreeTableView<String> treeView = new TreeTableView<>(); 3187 treeView.setRoot(root); 3188 3189 StageLoader sl = new StageLoader(treeView); 3190 3191 // Selection starts in row -1 3192 assertNull(treeView.getSelectionModel().getSelectedItem()); 3193 3194 // select "bbc" and ensure everything is set to that 3195 treeView.getSelectionModel().select(2); 3196 assertEquals("bbc", treeView.getSelectionModel().getSelectedItem().getValue()); 3197 3198 // change the items list - but retain the same content. We expect 3199 // that "bbc" remains selected as it is still in the list 3200 root.getChildren().setAll(aabbaa, bbc); 3201 assertEquals("bbc", treeView.getSelectionModel().getSelectedItem().getValue()); 3202 3203 sl.dispose(); 3204 } 3205 3206 @Test public void test_rt35763() { 3207 TreeItem<String> root = new TreeItem<>("Root"); 3208 root.setExpanded(true); 3209 TreeItem aaa = new TreeItem("aaa"); 3210 TreeItem bbb = new TreeItem("bbb"); 3211 root.getChildren().setAll(bbb, aaa); 3212 3213 final TreeTableView<String> treeView = new TreeTableView<>(); 3214 3215 TreeTableColumn<String, String> col = new TreeTableColumn<>("Column"); 3216 col.setCellValueFactory(param -> param.getValue().valueProperty()); 3217 3218 treeView.getColumns().add(col); 3219 treeView.setRoot(root); 3220 3221 assertEquals(root, treeView.getTreeItem(0)); 3222 assertEquals(bbb, treeView.getTreeItem(1)); 3223 assertEquals(aaa,treeView.getTreeItem(2)); 3224 3225 // change sort order - expect items to be sorted 3226 treeView.getSortOrder().setAll(col); 3227 3228 assertEquals(1, treeView.getSortOrder().size()); 3229 assertEquals(col, treeView.getSortOrder().get(0)); 3230 3231 Toolkit.getToolkit().firePulse(); 3232 3233 assertEquals(root, treeView.getTreeItem(0)); 3234 assertEquals(bbb, treeView.getTreeItem(2)); 3235 assertEquals(aaa,treeView.getTreeItem(1)); 3236 3237 // set new items into items list - expect sortOrder list to be reset 3238 // and the items list to remain unsorted 3239 TreeItem<String> root2 = new TreeItem<>("Root"); 3240 root2.setExpanded(true); 3241 TreeItem ccc = new TreeItem("ccc"); 3242 TreeItem ddd = new TreeItem("ddd"); 3243 root2.getChildren().setAll(ddd, ccc); 3244 treeView.setRoot(root2); 3245 3246 assertEquals(root2, treeView.getTreeItem(0)); 3247 assertEquals(ddd, treeView.getTreeItem(1)); 3248 assertEquals(ccc,treeView.getTreeItem(2)); 3249 3250 assertTrue(treeView.getSortOrder().isEmpty()); 3251 } 3252 3253 @Test public void test_rt35857() { 3254 TreeItem<String> root = new TreeItem<>("Root"); 3255 root.setExpanded(true); 3256 TreeItem a = new TreeItem("A"); 3257 TreeItem b = new TreeItem("B"); 3258 TreeItem c = new TreeItem("C"); 3259 root.getChildren().setAll(a, b, c); 3260 3261 final TreeTableView<String> treeTableView = new TreeTableView<String>(root); 3262 3263 treeTableView.getSelectionModel().select(1); 3264 3265 ObservableList<TreeItem<String>> selectedItems = treeTableView.getSelectionModel().getSelectedItems(); 3266 assertEquals(1, selectedItems.size()); 3267 assertEquals("A", selectedItems.get(0).getValue()); 3268 3269 root.getChildren().removeAll(selectedItems); 3270 assertEquals(2, root.getChildren().size()); 3271 assertEquals("B", root.getChildren().get(0).getValue()); 3272 assertEquals("C", root.getChildren().get(1).getValue()); 3273 } 3274 3275 private int rt36452_instanceCount = 0; 3276 @Test public void test_rt36452() { 3277 TreeTableColumn<String, String> myColumn = new TreeTableColumn<String,String>(); 3278 myColumn.setCellValueFactory((item)->(new ReadOnlyObjectWrapper<>(item.getValue().getValue()))); 3279 myColumn.setCellFactory(column -> new TreeTableCell<String, String>() { 3280 { 3281 rt36452_instanceCount++; 3282 } 3283 }); 3284 3285 TreeTableView<String> ttv = new TreeTableView<>(); 3286 ttv.setShowRoot(false); 3287 ttv.getColumns().add(myColumn); 3288 3289 TreeItem<String> treeRootItem = new TreeItem<>("root"); 3290 treeRootItem.setExpanded(true); 3291 3292 for (int i = 0; i < 100; i++) { 3293 treeRootItem.getChildren().add(new TreeItem<>("Child: " + i)); 3294 } 3295 3296 ttv.setRoot(treeRootItem); 3297 ttv.setFixedCellSize(25); 3298 3299 StackPane root = new StackPane(); 3300 root.getChildren().add(ttv); 3301 3302 StageLoader sl = new StageLoader(root); 3303 3304 final int cellCountAtStart = rt36452_instanceCount; 3305 3306 // start scrolling 3307 for (int i = 0; i < 100; i++) { 3308 ttv.scrollTo(i); 3309 Toolkit.getToolkit().firePulse(); 3310 } 3311 3312 // we don't mind if an extra few cells are created. What we are really 3313 // testing for here is that we don't end up with an order of magnitude 3314 // extra cells. 3315 // On my machine the cellCountAtStart is 16. Before this issue was fixed 3316 // I would end up with 102 instances after running this test. Once the 3317 // bug was fixed, I would consistently see that 17 cells had been 3318 // created in total. 3319 // However, for now, we'll test on the assumption that across all 3320 // platforms we only get one extra cell created, and we can loosen this 3321 // up if necessary. 3322 assertEquals(cellCountAtStart + 1, rt36452_instanceCount); 3323 3324 sl.dispose(); 3325 } 3326 3327 @Test public void test_rt25679_rowSelection() { 3328 test_rt25679(true); 3329 } 3330 3331 @Test public void test_rt25679_cellSelection() { 3332 test_rt25679(false); 3333 } 3334 3335 private void test_rt25679(boolean rowSelection) { 3336 Button focusBtn = new Button("Focus here"); 3337 3338 TreeItem<String> root = new TreeItem<>("Root"); 3339 root.getChildren().setAll(new TreeItem("a"), new TreeItem("b")); 3340 root.setExpanded(true); 3341 3342 final TreeTableView<String> treeView = new TreeTableView<>(root); 3343 TreeTableColumn<String, String> tableColumn = new TreeTableColumn<>(); 3344 tableColumn.setCellValueFactory(rowValue -> new SimpleStringProperty(rowValue.getValue().getValue())); 3345 treeView.getColumns().add(tableColumn); 3346 3347 TreeTableView.TreeTableViewSelectionModel<String> sm = treeView.getSelectionModel(); 3348 sm.setCellSelectionEnabled(! rowSelection); 3349 3350 VBox vbox = new VBox(focusBtn, treeView); 3351 3352 StageLoader sl = new StageLoader(vbox); 3353 sl.getStage().requestFocus(); 3354 focusBtn.requestFocus(); 3355 Toolkit.getToolkit().firePulse(); 3356 3357 // test initial state 3358 assertEquals(sl.getStage().getScene().getFocusOwner(), focusBtn); 3359 assertTrue(focusBtn.isFocused()); 3360 assertEquals(-1, sm.getSelectedIndex()); 3361 assertNull(sm.getSelectedItem()); 3362 3363 // move focus to the TreeTableView 3364 treeView.requestFocus(); 3365 3366 // ensure that there is a selection (where previously there was not one) 3367 assertEquals(sl.getStage().getScene().getFocusOwner(), treeView); 3368 assertTrue(treeView.isFocused()); 3369 3370 if (rowSelection) { 3371 assertEquals(0, sm.getSelectedIndices().size()); 3372 assertNull(sm.getSelectedItem()); 3373 assertFalse(sm.isSelected(0)); 3374 assertEquals(0, sm.getSelectedCells().size()); 3375 } else { 3376 assertFalse(sm.isSelected(0, tableColumn)); 3377 assertEquals(0, sm.getSelectedCells().size()); 3378 } 3379 3380 sl.dispose(); 3381 } 3382 3383 @Test public void test_rt36885() { 3384 test_rt36885(false); 3385 } 3386 3387 @Test public void test_rt36885_addChildAfterSelection() { 3388 test_rt36885(true); 3389 } 3390 3391 private void test_rt36885(boolean addChildToAAfterSelection) { 3392 TreeItem<String> root = new TreeItem<>("Root"); // 0 3393 TreeItem<String> a = new TreeItem<>("a"); // 1 3394 TreeItem<String> a1 = new TreeItem<>("a1"); // a expanded = 2, a collapsed = -1 3395 TreeItem<String> b = new TreeItem<>("b"); // a expanded = 3, a collapsed = 2 3396 TreeItem<String> b1 = new TreeItem<>("b1"); // a expanded = 4, a collapsed = 3 3397 TreeItem<String> b2 = new TreeItem<>("b2"); // a expanded = 5, a collapsed = 4 3398 3399 root.setExpanded(true); 3400 root.getChildren().setAll(a, b); 3401 3402 a.setExpanded(false); 3403 if (!addChildToAAfterSelection) { 3404 a.getChildren().add(a1); 3405 } 3406 3407 b.setExpanded(true); 3408 b.getChildren().addAll(b1, b2); 3409 3410 final TreeTableView<String> treeView = new TreeTableView<>(root); 3411 TreeTableColumn<String, String> tableColumn = new TreeTableColumn<>(); 3412 tableColumn.setCellValueFactory(rowValue -> new SimpleStringProperty(rowValue.getValue().getValue())); 3413 treeView.getColumns().add(tableColumn); 3414 3415 TreeTableView.TreeTableViewSelectionModel<String> sm = treeView.getSelectionModel(); 3416 FocusModel<TreeItem<String>> fm = treeView.getFocusModel(); 3417 3418 sm.select(b1); 3419 assertEquals(3, sm.getSelectedIndex()); 3420 assertEquals(b1, sm.getSelectedItem()); 3421 assertEquals(3, fm.getFocusedIndex()); 3422 assertEquals(b1, fm.getFocusedItem()); 3423 3424 if (addChildToAAfterSelection) { 3425 a.getChildren().add(a1); 3426 } 3427 3428 a.setExpanded(true); 3429 assertEquals(4, sm.getSelectedIndex()); 3430 assertEquals(b1, sm.getSelectedItem()); 3431 assertEquals(4, fm.getFocusedIndex()); 3432 assertEquals(b1, fm.getFocusedItem()); 3433 } 3434 3435 private int rt_37061_index_counter = 0; 3436 private int rt_37061_item_counter = 0; 3437 @Test public void test_rt_37061() { 3438 TreeItem<Integer> root = new TreeItem<>(0); 3439 root.setExpanded(true); 3440 TreeTableView<Integer> tv = new TreeTableView<>(); 3441 tv.setRoot(root); 3442 tv.getSelectionModel().select(0); 3443 3444 // note we add the listeners after the selection is made, so the counters 3445 // at this point are still both at zero. 3446 tv.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> { 3447 rt_37061_index_counter++; 3448 }); 3449 3450 tv.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { 3451 rt_37061_item_counter++; 3452 }); 3453 3454 // add a new item. This does not impact the selected index or selected item 3455 // so the counters should remain at zero. 3456 tv.getRoot().getChildren().add(new TreeItem("1")); 3457 assertEquals(0, rt_37061_index_counter); 3458 assertEquals(0, rt_37061_item_counter); 3459 } 3460 3461 @Test public void test_rt_37054_noScroll() { 3462 test_rt_37054(false); 3463 } 3464 3465 @Test public void test_rt_37054_scroll() { 3466 test_rt_37054(true); 3467 } 3468 3469 private void test_rt_37054(boolean scroll) { 3470 ObjectProperty<Integer> offset = new SimpleObjectProperty<Integer>(0); 3471 3472 // create table with a bunch of rows and 1 column... 3473 TreeItem<Integer> root = new TreeItem<>(0); 3474 root.setExpanded(true); 3475 for (int i = 1; i <= 50; i++) { 3476 root.getChildren().add(new TreeItem<>(i)); 3477 } 3478 3479 final TreeTableColumn<Integer, Integer> column = new TreeTableColumn<>("Column"); 3480 3481 final TreeTableView<Integer> table = new TreeTableView<>(root); 3482 table.getColumns().add( column ); 3483 column.setPrefWidth( 150 ); 3484 3485 // each cell displays x, where x = "cell row number + offset" 3486 column.setCellValueFactory( cdf -> new ObjectBinding<Integer>() { 3487 { super.bind( offset ); } 3488 3489 @Override protected Integer computeValue() { 3490 return cdf.getValue().getValue() + offset.get(); 3491 } 3492 }); 3493 3494 StackPane stack = new StackPane(); 3495 stack.getChildren().add(table); 3496 StageLoader sl = new StageLoader(stack); 3497 3498 int index = scroll ? 0 : 25; 3499 3500 if (scroll) { 3501 // we scroll to force the table cells to update the objects they observe 3502 table.scrollTo(index); 3503 Toolkit.getToolkit().firePulse(); 3504 } 3505 3506 TreeTableCell cell = (TreeTableCell) VirtualFlowTestUtils.getCell(table, index + 3, 0); 3507 final int initialValue = (Integer) cell.getItem(); 3508 3509 // increment the offset value 3510 offset.setValue(offset.get() + 1); 3511 Toolkit.getToolkit().firePulse(); 3512 3513 final int incrementedValue = (Integer) cell.getItem(); 3514 assertEquals(initialValue + 1, incrementedValue); 3515 3516 sl.dispose(); 3517 } 3518 3519 private int rt_37395_index_addCount = 0; 3520 private int rt_37395_index_removeCount = 0; 3521 private int rt_37395_index_permutationCount = 0; 3522 private int rt_37395_item_addCount = 0; 3523 private int rt_37395_item_removeCount = 0; 3524 private int rt_37395_item_permutationCount = 0; 3525 3526 @Test public void test_rt_37395() { 3527 // table items - 3 items, 2nd item has 2 children 3528 TreeItem<String> root = new TreeItem<>(); 3529 3530 TreeItem<String> two = new TreeItem<>("two"); 3531 two.getChildren().add(new TreeItem<>("childOne")); 3532 two.getChildren().add(new TreeItem<>("childTwo")); 3533 3534 root.getChildren().add(new TreeItem<>("one")); 3535 root.getChildren().add(two); 3536 root.getChildren().add(new TreeItem<>("three")); 3537 3538 // table columns - 1 column; name 3539 TreeTableColumn<String, String> nameColumn = new TreeTableColumn<>("name"); 3540 nameColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper(param.getValue().getValue())); 3541 nameColumn.setPrefWidth(200); 3542 3543 // table 3544 TreeTableView<String> table = new TreeTableView<>(); 3545 table.setShowRoot(false); 3546 table.setRoot(root); 3547 table.getColumns().addAll(nameColumn); 3548 3549 TreeTableView.TreeTableViewSelectionModel sm = table.getSelectionModel(); 3550 sm.getSelectedIndices().addListener(new ListChangeListener<Integer>() { 3551 @Override public void onChanged(Change<? extends Integer> c) { 3552 while (c.next()) { 3553 if (c.wasRemoved()) { 3554 c.getRemoved().forEach(item -> { 3555 if (item == null) { 3556 fail("Removed index should never be null"); 3557 } else { 3558 rt_37395_index_removeCount++; 3559 } 3560 }); 3561 } 3562 if (c.wasAdded()) { 3563 c.getAddedSubList().forEach(item -> { 3564 rt_37395_index_addCount++; 3565 }); 3566 } 3567 if (c.wasPermutated()) { 3568 rt_37395_index_permutationCount++; 3569 } 3570 } 3571 } 3572 }); 3573 sm.getSelectedItems().addListener(new ListChangeListener<TreeItem<String>>() { 3574 @Override public void onChanged(Change<? extends TreeItem<String>> c) { 3575 while (c.next()) { 3576 if (c.wasRemoved()) { 3577 c.getRemoved().forEach(item -> { 3578 if (item == null) { 3579 fail("Removed item should never be null"); 3580 } else { 3581 rt_37395_item_removeCount++; 3582 } 3583 }); 3584 } 3585 if (c.wasAdded()) { 3586 c.getAddedSubList().forEach(item -> { 3587 rt_37395_item_addCount++; 3588 }); 3589 } 3590 if (c.wasPermutated()) { 3591 rt_37395_item_permutationCount++; 3592 } 3593 } 3594 } 3595 }); 3596 3597 assertEquals(0, rt_37395_index_removeCount); 3598 assertEquals(0, rt_37395_index_addCount); 3599 assertEquals(0, rt_37395_index_permutationCount); 3600 assertEquals(0, rt_37395_item_removeCount); 3601 assertEquals(0, rt_37395_item_addCount); 3602 assertEquals(0, rt_37395_item_permutationCount); 3603 3604 StageLoader sl = new StageLoader(table); 3605 3606 // step one: select item 'three' in index 2 3607 sm.select(2); 3608 assertEquals(0, rt_37395_index_removeCount); 3609 assertEquals(1, rt_37395_index_addCount); 3610 assertEquals(0, rt_37395_index_permutationCount); 3611 assertEquals(0, rt_37395_item_removeCount); 3612 assertEquals(1, rt_37395_item_addCount); 3613 assertEquals(0, rt_37395_item_permutationCount); 3614 3615 // step two: expand item 'two' 3616 // The first part of the bug report was that we received add/remove 3617 // change events here, when in reality we shouldn't have, so lets enforce 3618 // that. We do expect a permutation event on the index, as it has been 3619 // pushed down, but this should not result in an item permutation event, 3620 // as it remains unchanged 3621 two.setExpanded(true); 3622 assertEquals(1, rt_37395_index_removeCount); 3623 assertEquals(2, rt_37395_index_addCount); 3624 assertEquals(0, rt_37395_index_permutationCount); 3625 assertEquals(0, rt_37395_item_removeCount); 3626 assertEquals(1, rt_37395_item_addCount); 3627 assertEquals(0, rt_37395_item_permutationCount); 3628 3629 // step three: collapse item 'two' 3630 // Same argument as in step two above: no addition or removal, just a 3631 // permutation on the index 3632 two.setExpanded(false); 3633 assertEquals(2, rt_37395_index_removeCount); 3634 assertEquals(3, rt_37395_index_addCount); 3635 assertEquals(0, rt_37395_index_permutationCount); 3636 assertEquals(0, rt_37395_item_removeCount); 3637 assertEquals(1, rt_37395_item_addCount); 3638 assertEquals(0, rt_37395_item_permutationCount); 3639 3640 sl.dispose(); 3641 } 3642 3643 @Test public void test_rt_37429() { 3644 // table items - 3 items, 2nd item has 2 children 3645 TreeItem<String> root = new TreeItem<>(); 3646 3647 TreeItem<String> two = new TreeItem<>("two"); 3648 two.getChildren().add(new TreeItem<>("childOne")); 3649 two.getChildren().add(new TreeItem<>("childTwo")); 3650 two.setExpanded(true); 3651 3652 root.getChildren().add(new TreeItem<>("one")); 3653 root.getChildren().add(two); 3654 root.getChildren().add(new TreeItem<>("three")); 3655 3656 // table columns - 1 column; name 3657 TreeTableColumn<String, String> nameColumn = new TreeTableColumn<>("name"); 3658 nameColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper(param.getValue().getValue())); 3659 nameColumn.setPrefWidth(200); 3660 3661 // table 3662 TreeTableView<String> table = new TreeTableView<>(); 3663 table.setShowRoot(false); 3664 table.setRoot(root); 3665 table.getColumns().addAll(nameColumn); 3666 3667 table.getSelectionModel().getSelectedItems().addListener((ListChangeListener<TreeItem<String>>) c -> { 3668 while (c.next()) { 3669 if(c.wasRemoved()) { 3670 // The removed list of items must be iterated or the AIOOBE will 3671 // not be thrown when getAddedSubList is called. 3672 c.getRemoved().forEach(item -> {}); 3673 } 3674 3675 if (c.wasAdded()) { 3676 c.getAddedSubList(); 3677 } 3678 } 3679 }); 3680 3681 StageLoader sl = new StageLoader(table); 3682 3683 ControlTestUtils.runWithExceptionHandler(() -> { 3684 table.getSelectionModel().select(0); 3685 table.getSortOrder().add(nameColumn); 3686 }); 3687 3688 sl.dispose(); 3689 } 3690 3691 private int rt_37429_items_change_count = 0; 3692 private int rt_37429_cells_change_count = 0; 3693 @Test public void test_rt_37429_sortEventsShouldNotFireExtraChangeEvents() { 3694 // table items - 3 items, 2nd item has 2 children 3695 TreeItem<String> root = new TreeItem<>(); 3696 3697 root.getChildren().add(new TreeItem<>("a")); 3698 root.getChildren().add(new TreeItem<>("c")); 3699 root.getChildren().add(new TreeItem<>("b")); 3700 3701 // table columns - 1 column; name 3702 TreeTableColumn<String, String> nameColumn = new TreeTableColumn<>("name"); 3703 nameColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper(param.getValue().getValue())); 3704 nameColumn.setPrefWidth(200); 3705 3706 // table 3707 TreeTableView<String> table = new TreeTableView<>(); 3708 table.setShowRoot(false); 3709 table.setRoot(root); 3710 table.getColumns().addAll(nameColumn); 3711 3712 table.getSelectionModel().getSelectedItems().addListener((ListChangeListener<TreeItem<String>>) c -> { 3713 while (c.next()) { 3714 rt_37429_items_change_count++; 3715 } 3716 }); 3717 table.getSelectionModel().getSelectedCells().addListener((ListChangeListener<TreeTablePosition<String, ?>>) c -> { 3718 while (c.next()) { 3719 rt_37429_cells_change_count++; 3720 } 3721 }); 3722 3723 StageLoader sl = new StageLoader(table); 3724 3725 assertEquals(0, rt_37429_items_change_count); 3726 assertEquals(0, rt_37429_cells_change_count); 3727 3728 table.getSelectionModel().select(0); 3729 assertEquals(1, rt_37429_items_change_count); 3730 assertEquals(1, rt_37429_cells_change_count); 3731 3732 table.getSortOrder().add(nameColumn); 3733 assertEquals(1, rt_37429_items_change_count); 3734 assertEquals(1, rt_37429_cells_change_count); 3735 3736 nameColumn.setSortType(TreeTableColumn.SortType.DESCENDING); 3737 assertEquals(1, rt_37429_items_change_count); 3738 assertEquals(2, rt_37429_cells_change_count); 3739 3740 nameColumn.setSortType(TreeTableColumn.SortType.ASCENDING); 3741 assertEquals(1, rt_37429_items_change_count); 3742 assertEquals(3, rt_37429_cells_change_count); 3743 3744 sl.dispose(); 3745 } 3746 3747 private int rt_37538_count = 0; 3748 @Test public void test_rt_37538_noCNextCall() { 3749 test_rt_37538(false, false); 3750 } 3751 3752 @Test public void test_rt_37538_callCNextOnce() { 3753 test_rt_37538(true, false); 3754 } 3755 3756 @Test public void test_rt_37538_callCNextInLoop() { 3757 test_rt_37538(false, true); 3758 } 3759 3760 private void test_rt_37538(boolean callCNextOnce, boolean callCNextInLoop) { 3761 // create table with a bunch of rows and 1 column... 3762 TreeItem<Integer> root = new TreeItem<>(0); 3763 root.setExpanded(true); 3764 for (int i = 1; i <= 50; i++) { 3765 root.getChildren().add(new TreeItem<>(i)); 3766 } 3767 3768 final TreeTableColumn<Integer, Integer> column = new TreeTableColumn<>("Column"); 3769 column.setCellValueFactory( cdf -> new ReadOnlyObjectWrapper<Integer>(cdf.getValue().getValue())); 3770 3771 final TreeTableView<Integer> table = new TreeTableView<>(root); 3772 table.getColumns().add( column ); 3773 3774 table.getSelectionModel().getSelectedItems().addListener((ListChangeListener.Change<? extends TreeItem<Integer>> c) -> { 3775 if (callCNextOnce) { 3776 c.next(); 3777 } else if (callCNextInLoop) { 3778 while (c.next()) { 3779 // no-op 3780 } 3781 } 3782 3783 if (rt_37538_count >= 1) { 3784 Thread.dumpStack(); 3785 fail("This method should only be called once"); 3786 } 3787 3788 rt_37538_count++; 3789 }); 3790 3791 StageLoader sl = new StageLoader(table); 3792 assertEquals(0, rt_37538_count); 3793 table.getSelectionModel().select(0); 3794 assertEquals(1, rt_37538_count); 3795 sl.dispose(); 3796 } 3797 3798 @Test public void test_rt_37593() { 3799 TreeItem<String> root = new TreeItem<>(); 3800 3801 TreeItem<String> one = new TreeItem<>("one"); 3802 root.getChildren().add(one); 3803 3804 TreeItem<String> two = new TreeItem<>("two"); 3805 two.getChildren().add(new TreeItem<>("childOne")); 3806 two.getChildren().add(new TreeItem<>("childTwo")); 3807 root.getChildren().add(two); 3808 3809 root.getChildren().add(new TreeItem<>("three")); 3810 3811 TreeTableColumn<String, String> nameColumn = new TreeTableColumn<>("name"); 3812 nameColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper(param.getValue().getValue())); 3813 3814 treeTableView.setShowRoot(false); 3815 treeTableView.setRoot(root); 3816 treeTableView.getColumns().addAll(nameColumn); 3817 3818 treeTableView.getSortOrder().add(nameColumn); 3819 nameColumn.setSortType(TreeTableColumn.SortType.DESCENDING); 3820 sm.select(one); 3821 3822 // at this point, the 'one' item should be in row 2 3823 assertTrue(sm.isSelected(2)); 3824 assertEquals(one, sm.getSelectedItem()); 3825 3826 two.setExpanded(true); 3827 3828 // we should end up with the selection being on index 4, which is the 3829 // final location of the 'one' tree item, after sorting and expanding 'two' 3830 assertEquals(one, sm.getSelectedItem()); 3831 assertTrue(debug(), sm.isSelected(4)); 3832 3833 // this line would create a NPE 3834 VirtualFlowTestUtils.clickOnRow(treeTableView, 4, true); 3835 3836 // The mouse click should not change selection at all 3837 assertEquals(one, sm.getSelectedItem()); 3838 assertTrue(debug(), sm.isSelected(4)); 3839 } 3840 3841 @Test public void test_rt_35395_testCell_fixedCellSize() { 3842 test_rt_35395(true, true); 3843 } 3844 3845 @Test public void test_rt_35395_testCell_notFixedCellSize() { 3846 test_rt_35395(true, false); 3847 } 3848 3849 @Ignore("Fix not yet developed for TreeTableView") 3850 @Test public void test_rt_35395_testRow_fixedCellSize() { 3851 test_rt_35395(false, true); 3852 } 3853 3854 @Ignore("Fix not yet developed for TreeTableView") 3855 @Test public void test_rt_35395_testRow_notFixedCellSize() { 3856 test_rt_35395(false, false); 3857 } 3858 3859 private int rt_35395_counter; 3860 private void test_rt_35395(boolean testCell, boolean useFixedCellSize) { 3861 rt_35395_counter = 0; 3862 3863 TreeItem<String> root = new TreeItem<>("green"); 3864 root.setExpanded(true); 3865 for (int i = 0; i < 20; i++) { 3866 root.getChildren().addAll(new TreeItem<>("red"), new TreeItem<>("green"), new TreeItem<>("blue"), new TreeItem<>("purple")); 3867 } 3868 3869 TreeTableView<String> treeTableView = new TreeTableView<>(root); 3870 if (useFixedCellSize) { 3871 treeTableView.setFixedCellSize(24); 3872 } 3873 treeTableView.setRowFactory(tv -> new TreeTableRowShim<String>() { 3874 @Override public void updateItem(String color, boolean empty) { 3875 rt_35395_counter += testCell ? 0 : 1; 3876 super.updateItem(color, empty); 3877 } 3878 }); 3879 3880 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 3881 column.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue())); 3882 column.setCellFactory(tv -> new TreeTableCellShim<String,String>() { 3883 @Override public void updateItem(String color, boolean empty) { 3884 rt_35395_counter += testCell ? 1 : 0; 3885 super.updateItem(color, empty); 3886 setText(null); 3887 if (empty) { 3888 setGraphic(null); 3889 } else { 3890 Rectangle rect = new Rectangle(16, 16); 3891 rect.setStyle("-fx-fill: " + color); 3892 setGraphic(rect); 3893 } 3894 } 3895 }); 3896 treeTableView.getColumns().addAll(column); 3897 3898 StageLoader sl = new StageLoader(treeTableView); 3899 3900 Platform.runLater(() -> { 3901 rt_35395_counter = 0; 3902 root.getChildren().set(10, new TreeItem<>("yellow")); 3903 Platform.runLater(() -> { 3904 Toolkit.getToolkit().firePulse(); 3905 assertEquals(1, rt_35395_counter); 3906 rt_35395_counter = 0; 3907 root.getChildren().set(30, new TreeItem<>("yellow")); 3908 Platform.runLater(() -> { 3909 Toolkit.getToolkit().firePulse(); 3910 assertEquals(0, rt_35395_counter); 3911 rt_35395_counter = 0; 3912 treeTableView.scrollTo(5); 3913 Platform.runLater(() -> { 3914 Toolkit.getToolkit().firePulse(); 3915 assertEquals(useFixedCellSize ? 5 : 5, rt_35395_counter); 3916 rt_35395_counter = 0; 3917 treeTableView.scrollTo(55); 3918 Platform.runLater(() -> { 3919 Toolkit.getToolkit().firePulse(); 3920 3921 assertEquals(useFixedCellSize ? 7 : 59, rt_35395_counter); 3922 sl.dispose(); 3923 }); 3924 }); 3925 }); 3926 }); 3927 }); 3928 } 3929 3930 @Test public void test_rt_37632() { 3931 final TreeItem<String> rootOne = new TreeItem<>("Root 1"); 3932 final TreeItem<String> rootTwo = new TreeItem<>("Root 2"); 3933 3934 TreeTableColumn<String,String> tableColumn = new TreeTableColumn("column"); 3935 tableColumn.setCellValueFactory(c -> new ReadOnlyStringWrapper(c.getValue().getValue())); 3936 3937 final TreeTableView<String> treeTableView = new TreeTableView<>(); 3938 treeTableView.getColumns().addAll(tableColumn); 3939 MultipleSelectionModel<TreeItem<String>> sm = treeTableView.getSelectionModel(); 3940 treeTableView.setRoot(rootOne); 3941 treeTableView.getSelectionModel().selectFirst(); 3942 3943 assertEquals(0, sm.getSelectedIndex()); 3944 assertEquals(rootOne, sm.getSelectedItem()); 3945 assertEquals(1, sm.getSelectedIndices().size()); 3946 assertEquals(0, (int) sm.getSelectedIndices().get(0)); 3947 assertEquals(1, sm.getSelectedItems().size()); 3948 assertEquals(rootOne, sm.getSelectedItems().get(0)); 3949 3950 treeTableView.setRoot(rootTwo); 3951 3952 assertEquals(-1, sm.getSelectedIndex()); 3953 assertNull(sm.getSelectedItem()); 3954 assertEquals(0, sm.getSelectedIndices().size()); 3955 assertEquals(0, sm.getSelectedItems().size()); 3956 } 3957 3958 private TreeTableView<Person> test_rt_38464_createControl() { 3959 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 3960 new TreeItem<>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 3961 new TreeItem<>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 3962 new TreeItem<>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 3963 new TreeItem<>(new Person("Emma", "Jones", "emma.jones@example.com")), 3964 new TreeItem<>(new Person("Michael", "Brown", "michael.brown@example.com"))); 3965 3966 TreeTableView<Person> table = new TreeTableView<>(); 3967 table.setShowRoot(false); 3968 3969 TreeItem<Person> root = new TreeItem<>(new Person("Root", null, null)); 3970 root.setExpanded(true); 3971 root.getChildren().setAll(persons); 3972 table.setRoot(root); 3973 3974 3975 3976 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 3977 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 3978 3979 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 3980 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 3981 3982 table.getColumns().addAll(firstNameCol, lastNameCol); 3983 3984 return table; 3985 } 3986 3987 @Test public void test_rt_38464_rowSelection_selectFirstRowOnly() { 3988 TreeTableView<Person> table = test_rt_38464_createControl(); 3989 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 3990 sm.setCellSelectionEnabled(false); 3991 sm.setSelectionMode(SelectionMode.MULTIPLE); 3992 3993 sm.select(0); 3994 3995 assertTrue(sm.isSelected(0)); 3996 assertTrue(sm.isSelected(0, table.getColumns().get(0))); 3997 assertTrue(sm.isSelected(0, table.getColumns().get(1))); 3998 3999 assertEquals(1, sm.getSelectedIndices().size()); 4000 assertEquals(1, sm.getSelectedItems().size()); 4001 assertEquals(1, sm.getSelectedCells().size()); 4002 } 4003 4004 @Test public void test_rt_38464_rowSelection_selectFirstRowAndThenCallNoOpMethods() { 4005 TreeTableView<Person> table = test_rt_38464_createControl(); 4006 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 4007 sm.setCellSelectionEnabled(false); 4008 sm.setSelectionMode(SelectionMode.MULTIPLE); 4009 4010 sm.select(0); // select first row 4011 sm.select(0); // this should be a no-op 4012 sm.select(0, table.getColumns().get(0)); // so should this, as we are in row selection mode 4013 sm.select(0, table.getColumns().get(1)); // and same here 4014 4015 assertTrue(sm.isSelected(0)); 4016 assertTrue(sm.isSelected(0, table.getColumns().get(0))); 4017 assertTrue(sm.isSelected(0, table.getColumns().get(1))); 4018 4019 assertEquals(1, sm.getSelectedIndices().size()); 4020 assertEquals(1, sm.getSelectedItems().size()); 4021 assertEquals(1, sm.getSelectedCells().size()); 4022 } 4023 4024 4025 @Test public void test_rt_38464_cellSelection_selectFirstRowOnly() { 4026 TreeTableView<Person> table = test_rt_38464_createControl(); 4027 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 4028 sm.setCellSelectionEnabled(true); 4029 sm.setSelectionMode(SelectionMode.MULTIPLE); 4030 4031 // select first row. This should be translated into selection of all 4032 // cells in this row, and (as of JDK 9) _does_ result in the row itself being 4033 // considered selected. 4034 sm.select(0); 4035 4036 assertTrue(sm.isSelected(0)); 4037 assertTrue(sm.isSelected(0, table.getColumns().get(0))); 4038 assertTrue(sm.isSelected(0, table.getColumns().get(1))); 4039 4040 assertEquals(1, sm.getSelectedIndices().size()); 4041 assertEquals(1, sm.getSelectedItems().size()); 4042 assertEquals(2, sm.getSelectedCells().size()); 4043 } 4044 4045 @Test public void test_rt_38464_cellSelection_selectFirstRowAndThenCallNoOpMethods() { 4046 TreeTableView<Person> table = test_rt_38464_createControl(); 4047 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 4048 sm.setCellSelectionEnabled(true); 4049 sm.setSelectionMode(SelectionMode.MULTIPLE); 4050 4051 // select first row. This should be translated into selection of all 4052 // cells in this row, and (as of JDK 9) _does_ result in the row itself being 4053 // considered selected. 4054 sm.select(0); // select first row 4055 sm.select(0, table.getColumns().get(0)); // This line and the next should be no-ops 4056 sm.select(0, table.getColumns().get(1)); 4057 4058 assertTrue(sm.isSelected(0)); 4059 assertTrue(sm.isSelected(0, table.getColumns().get(0))); 4060 assertTrue(sm.isSelected(0, table.getColumns().get(1))); 4061 4062 assertEquals(1, sm.getSelectedIndices().size()); 4063 assertEquals(1, sm.getSelectedItems().size()); 4064 assertEquals(2, sm.getSelectedCells().size()); 4065 } 4066 4067 @Test public void test_rt38464_selectCellMultipleTimes() { 4068 TreeTableView<Person> table = test_rt_38464_createControl(); 4069 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 4070 sm.setCellSelectionEnabled(true); 4071 sm.setSelectionMode(SelectionMode.MULTIPLE); 4072 4073 // default selection when in cell selection mode 4074 assertEquals(0, sm.getSelectedCells().size()); 4075 assertEquals(0, sm.getSelectedItems().size()); 4076 assertEquals(0, sm.getSelectedIndices().size()); 4077 4078 // select the first cell 4079 sm.select(0, table.getColumns().get(0)); 4080 assertEquals(1, sm.getSelectedCells().size()); 4081 assertEquals(1, sm.getSelectedItems().size()); 4082 assertEquals(1, sm.getSelectedIndices().size()); 4083 4084 // select the first cell....again 4085 sm.select(0, table.getColumns().get(0)); 4086 assertEquals(1, sm.getSelectedCells().size()); 4087 assertEquals(1, sm.getSelectedItems().size()); 4088 assertEquals(1, sm.getSelectedIndices().size()); 4089 } 4090 4091 @Test public void test_rt38464_selectCellThenRow() { 4092 TreeTableView<Person> table = test_rt_38464_createControl(); 4093 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 4094 sm.setCellSelectionEnabled(true); 4095 sm.setSelectionMode(SelectionMode.MULTIPLE); 4096 4097 // default selection when in cell selection mode 4098 assertEquals(0, sm.getSelectedCells().size()); 4099 assertEquals(0, sm.getSelectedItems().size()); 4100 assertEquals(0, sm.getSelectedIndices().size()); 4101 4102 // select the first cell 4103 sm.select(0, table.getColumns().get(0)); 4104 assertEquals(1, sm.getSelectedCells().size()); 4105 assertEquals(1, sm.getSelectedItems().size()); 4106 assertEquals(1, sm.getSelectedIndices().size()); 4107 4108 // select the first row 4109 sm.select(0); 4110 4111 // we go to 2 here as all cells in the row become selected. What we do 4112 // not expect is to go to 3, as that would mean duplication 4113 assertEquals(2, sm.getSelectedCells().size()); 4114 assertEquals(1, sm.getSelectedItems().size()); 4115 assertEquals(1, sm.getSelectedIndices().size()); 4116 } 4117 4118 @Test public void test_rt38464_selectRowThenCell() { 4119 TreeTableView<Person> table = test_rt_38464_createControl(); 4120 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 4121 sm.setCellSelectionEnabled(true); 4122 sm.setSelectionMode(SelectionMode.MULTIPLE); 4123 4124 // default selection when in cell selection mode 4125 assertEquals(0, sm.getSelectedCells().size()); 4126 assertEquals(0, sm.getSelectedItems().size()); 4127 assertEquals(0, sm.getSelectedIndices().size()); 4128 4129 // select the first row 4130 sm.select(0); 4131 4132 // we go to 2 here as all cells in the row become selected. 4133 assertEquals(2, sm.getSelectedCells().size()); 4134 assertEquals(1, sm.getSelectedItems().size()); 4135 assertEquals(1, sm.getSelectedIndices().size()); 4136 4137 // select the first cell - no change is expected 4138 sm.select(0, table.getColumns().get(0)); 4139 assertEquals(2, sm.getSelectedCells().size()); 4140 assertEquals(1, sm.getSelectedItems().size()); 4141 assertEquals(1, sm.getSelectedIndices().size()); 4142 } 4143 4144 @Test public void test_rt38464_selectTests_cellSelection_singleSelection_selectsOneRow() { 4145 test_rt38464_selectTests(true, true, true); 4146 } 4147 4148 @Test public void test_rt38464_selectTests_cellSelection_singleSelection_selectsTwoRows() { 4149 test_rt38464_selectTests(true, true, false); 4150 } 4151 4152 @Test public void test_rt38464_selectTests_cellSelection_multipleSelection_selectsOneRow() { 4153 test_rt38464_selectTests(true, false, true); 4154 } 4155 4156 @Test public void test_rt38464_selectTests_cellSelection_multipleSelection_selectsTwoRows() { 4157 test_rt38464_selectTests(true, false, false); 4158 } 4159 4160 @Test public void test_rt38464_selectTests_rowSelection_singleSelection_selectsOneRow() { 4161 test_rt38464_selectTests(false, true, true); 4162 } 4163 4164 @Test public void test_rt38464_selectTests_rowSelection_singleSelection_selectsTwoRows() { 4165 test_rt38464_selectTests(false, true, false); 4166 } 4167 4168 @Test public void test_rt38464_selectTests_rowSelection_multipleSelection_selectsOneRow() { 4169 test_rt38464_selectTests(false, false, true); 4170 } 4171 4172 @Test public void test_rt38464_selectTests_rowSelection_multipleSelection_selectsTwoRows() { 4173 test_rt38464_selectTests(false, false, false); 4174 } 4175 4176 private void test_rt38464_selectTests(boolean cellSelection, boolean singleSelection, boolean selectsOneRow) { 4177 TreeTableView<Person> table = test_rt_38464_createControl(); 4178 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 4179 sm.setCellSelectionEnabled(cellSelection); 4180 sm.setSelectionMode(singleSelection ? SelectionMode.SINGLE : SelectionMode.MULTIPLE); 4181 4182 // default selection when in cell selection mode 4183 assertEquals(0, sm.getSelectedCells().size()); 4184 assertEquals(0, sm.getSelectedItems().size()); 4185 assertEquals(0, sm.getSelectedIndices().size()); 4186 4187 if (selectsOneRow) { 4188 sm.select(0); 4189 } else { 4190 // select the first two rows 4191 sm.selectIndices(0, 1); 4192 } 4193 4194 final int expectedCells = singleSelection ? 1 : 4195 selectsOneRow && cellSelection ? 2 : 4196 selectsOneRow && !cellSelection ? 1 : 4197 !selectsOneRow && cellSelection ? 4 : 4198 /* !selectsOneRow && !cellSelection */ 2; 4199 4200 final int expectedItems = singleSelection ? 1 : 4201 selectsOneRow ? 1 : 2; 4202 4203 assertEquals(expectedCells, sm.getSelectedCells().size()); 4204 assertEquals(expectedItems, sm.getSelectedItems().size()); 4205 assertEquals(expectedItems, sm.getSelectedIndices().size()); 4206 4207 // we expect the table column of all selected cells, in this instance, 4208 // to be null as we have not explicitly stated a column, nor have we clicked 4209 // on a column. The only alternative is to use the first column. 4210 for (TreeTablePosition<?,?> tp : sm.getSelectedCells()) { 4211 if (cellSelection) { 4212 assertNotNull(tp.getTableColumn()); 4213 } else { 4214 assertNull(tp.getTableColumn()); 4215 } 4216 } 4217 } 4218 4219 @Test public void test_rt_37853_replaceRoot() { 4220 test_rt_37853(true); 4221 } 4222 4223 @Test public void test_rt_37853_replaceRootChildren() { 4224 test_rt_37853(false); 4225 } 4226 4227 private int rt_37853_cancelCount; 4228 private int rt_37853_commitCount; 4229 public void test_rt_37853(boolean replaceRoot) { 4230 TreeTableColumn<String,String> first = new TreeTableColumn<>("first"); 4231 first.setEditable(true); 4232 first.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn()); 4233 treeTableView.getColumns().add(first); 4234 treeTableView.setEditable(true); 4235 treeTableView.setRoot(new TreeItem<>("Root")); 4236 treeTableView.getRoot().setExpanded(true); 4237 4238 for (int i = 0; i < 10; i++) { 4239 treeTableView.getRoot().getChildren().add(new TreeItem<>("" + i)); 4240 } 4241 4242 StageLoader sl = new StageLoader(treeTableView); 4243 4244 first.setOnEditCancel(editEvent -> rt_37853_cancelCount++); 4245 first.setOnEditCommit(editEvent -> rt_37853_commitCount++); 4246 4247 assertEquals(0, rt_37853_cancelCount); 4248 assertEquals(0, rt_37853_commitCount); 4249 4250 treeTableView.edit(1, first); 4251 assertNotNull(treeTableView.getEditingCell()); 4252 4253 if (replaceRoot) { 4254 treeTableView.setRoot(new TreeItem<>("New Root")); 4255 } else { 4256 treeTableView.getRoot().getChildren().clear(); 4257 for (int i = 0; i < 10; i++) { 4258 treeTableView.getRoot().getChildren().add(new TreeItem<>("new item " + i)); 4259 } 4260 } 4261 assertEquals(1, rt_37853_cancelCount); 4262 assertEquals(0, rt_37853_commitCount); 4263 4264 sl.dispose(); 4265 } 4266 4267 4268 /************************************************************************** 4269 * 4270 * Tests (and related code) for RT-38892 4271 * 4272 *************************************************************************/ 4273 4274 private final Supplier<TreeTableColumn<Person,String>> columnCallable = () -> { 4275 TreeTableColumn<Person,String> column = new TreeTableColumn<>("Last Name"); 4276 column.setCellValueFactory(new TreeItemPropertyValueFactory<Person,String>("lastName")); 4277 return column; 4278 }; 4279 4280 private TreeTableColumn<Person, String> test_rt_38892_firstNameCol; 4281 private TreeTableColumn<Person, String> test_rt_38892_lastNameCol; 4282 4283 private TreeTableView<Person> init_test_rt_38892() { 4284 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 4285 new TreeItem<>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 4286 new TreeItem<>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 4287 new TreeItem<>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 4288 new TreeItem<>(new Person("Emma", "Jones", "emma.jones@example.com")), 4289 new TreeItem<>(new Person("Michael", "Brown", "michael.brown@example.com"))); 4290 4291 TreeTableView<Person> table = new TreeTableView<>(); 4292 table.setShowRoot(false); 4293 table.getSelectionModel().setCellSelectionEnabled(true); 4294 table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 4295 4296 TreeItem<Person> root = new TreeItem<>(new Person("Root", null, null)); 4297 root.setExpanded(true); 4298 root.getChildren().setAll(persons); 4299 table.setRoot(root); 4300 4301 test_rt_38892_firstNameCol = new TreeTableColumn<>("First Name"); 4302 test_rt_38892_firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<>("firstName")); 4303 test_rt_38892_lastNameCol = columnCallable.get(); 4304 table.getColumns().addAll(test_rt_38892_firstNameCol, test_rt_38892_lastNameCol); 4305 4306 return table; 4307 } 4308 4309 @Test public void test_rt_38892_focusMovesToLeftWhenPossible() { 4310 TreeTableView<Person> table = init_test_rt_38892(); 4311 4312 TreeTableView.TreeTableViewFocusModel<Person> fm = table.getFocusModel(); 4313 fm.focus(0, test_rt_38892_lastNameCol); 4314 4315 // assert pre-conditions 4316 assertEquals(0, fm.getFocusedIndex()); 4317 assertEquals(0, fm.getFocusedCell().getRow()); 4318 assertEquals(test_rt_38892_lastNameCol, fm.getFocusedCell().getTableColumn()); 4319 assertEquals(1, fm.getFocusedCell().getColumn()); 4320 4321 // now remove column where focus is and replace it with a new column. 4322 // We expect focus to move to the left one cell. 4323 table.getColumns().remove(1); 4324 table.getColumns().add(columnCallable.get()); 4325 4326 assertEquals(0, fm.getFocusedIndex()); 4327 assertEquals(0, fm.getFocusedCell().getRow()); 4328 assertEquals(test_rt_38892_firstNameCol, fm.getFocusedCell().getTableColumn()); 4329 assertEquals(0, fm.getFocusedCell().getColumn()); 4330 } 4331 4332 @Test public void test_rt_38892_removeLeftMostColumn() { 4333 TreeTableView<Person> table = init_test_rt_38892(); 4334 4335 TreeTableView.TreeTableViewFocusModel<Person> fm = table.getFocusModel(); 4336 fm.focus(0, test_rt_38892_firstNameCol); 4337 4338 // assert pre-conditions 4339 assertEquals(0, fm.getFocusedIndex()); 4340 assertEquals(0, fm.getFocusedCell().getRow()); 4341 assertEquals(test_rt_38892_firstNameCol, fm.getFocusedCell().getTableColumn()); 4342 assertEquals(0, fm.getFocusedCell().getColumn()); 4343 4344 // now remove column where focus is and replace it with a new column. 4345 // In the current (non-specified) behavior, this results in focus being 4346 // shifted to a cell in the remaining column, even when we add a new column 4347 // as we index based on the column, not on its index. 4348 table.getColumns().remove(0); 4349 TreeTableColumn<Person,String> newColumn = columnCallable.get(); 4350 table.getColumns().add(0, newColumn); 4351 4352 assertEquals(0, fm.getFocusedIndex()); 4353 assertEquals(0, fm.getFocusedCell().getRow()); 4354 assertEquals(test_rt_38892_lastNameCol, fm.getFocusedCell().getTableColumn()); 4355 assertEquals(0, fm.getFocusedCell().getColumn()); 4356 } 4357 4358 @Test public void test_rt_38892_removeSelectionFromCellsInRemovedColumn() { 4359 TreeTableView<Person> table = init_test_rt_38892(); 4360 4361 TreeTableView.TreeTableViewSelectionModel sm = table.getSelectionModel(); 4362 sm.select(0, test_rt_38892_firstNameCol); 4363 sm.select(1, test_rt_38892_lastNameCol); // this should go 4364 sm.select(2, test_rt_38892_firstNameCol); 4365 sm.select(3, test_rt_38892_lastNameCol); // so should this 4366 sm.select(4, test_rt_38892_firstNameCol); 4367 4368 assertEquals(5, sm.getSelectedCells().size()); 4369 4370 table.getColumns().remove(1); 4371 4372 assertEquals(3, sm.getSelectedCells().size()); 4373 assertTrue(sm.isSelected(0, test_rt_38892_firstNameCol)); 4374 assertFalse(sm.isSelected(1, test_rt_38892_lastNameCol)); 4375 assertTrue(sm.isSelected(2, test_rt_38892_firstNameCol)); 4376 assertFalse(sm.isSelected(3, test_rt_38892_lastNameCol)); 4377 assertTrue(sm.isSelected(4, test_rt_38892_firstNameCol)); 4378 } 4379 4380 @Test public void test_rt_38787_remove_b() { 4381 // Remove 'b', selection moves to 'a' 4382 test_rt_38787("a", 0, 1); 4383 } 4384 4385 @Test public void test_rt_38787_remove_b_c() { 4386 // Remove 'b' and 'c', selection moves to 'a' 4387 test_rt_38787("a", 0, 1, 2); 4388 } 4389 4390 @Test public void test_rt_38787_remove_c_d() { 4391 // Remove 'c' and 'd', selection moves to 'b' 4392 test_rt_38787("b", 1, 2, 3); 4393 } 4394 4395 @Test public void test_rt_38787_remove_a() { 4396 // Remove 'a', selection moves to 'b', now in index 0 4397 test_rt_38787("b", 0, 0); 4398 } 4399 4400 private void test_rt_38787(String expectedItem, int expectedIndex, int... indicesToRemove) { 4401 TreeItem<String> a, b, c, d; 4402 TreeItem<String> root = new TreeItem<>("Root"); 4403 root.setExpanded(true); 4404 root.getChildren().addAll( 4405 a = new TreeItem<String>("a"), 4406 b = new TreeItem<String>("b"), 4407 c = new TreeItem<String>("c"), 4408 d = new TreeItem<String>("d") 4409 ); 4410 4411 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4412 stringTreeTableView.setShowRoot(false); 4413 4414 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4415 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4416 stringTreeTableView.getColumns().add(column); 4417 4418 MultipleSelectionModel<TreeItem<String>> sm = stringTreeTableView.getSelectionModel(); 4419 sm.select(b); 4420 4421 // test pre-conditions 4422 assertEquals(1, sm.getSelectedIndex()); 4423 assertEquals(1, (int)sm.getSelectedIndices().get(0)); 4424 assertEquals(b, sm.getSelectedItem()); 4425 assertEquals(b, sm.getSelectedItems().get(0)); 4426 assertFalse(sm.isSelected(0)); 4427 assertTrue(sm.isSelected(1)); 4428 assertFalse(sm.isSelected(2)); 4429 4430 // removing items 4431 List<TreeItem<String>> itemsToRemove = new ArrayList<>(indicesToRemove.length); 4432 for (int index : indicesToRemove) { 4433 itemsToRemove.add(root.getChildren().get(index)); 4434 } 4435 root.getChildren().removeAll(itemsToRemove); 4436 4437 // testing against expectations 4438 assertEquals(expectedIndex, sm.getSelectedIndex()); 4439 assertEquals(expectedIndex, (int)sm.getSelectedIndices().get(0)); 4440 assertEquals(expectedItem, sm.getSelectedItem().getValue()); 4441 assertEquals(expectedItem, sm.getSelectedItems().get(0).getValue()); 4442 } 4443 4444 private int rt_38341_indices_count = 0; 4445 private int rt_38341_items_count = 0; 4446 @Test public void test_rt_38341() { 4447 Callback<Integer, TreeItem<String>> callback = number -> { 4448 final TreeItem<String> root = new TreeItem<>("Root " + number); 4449 final TreeItem<String> child = new TreeItem<>("Child " + number); 4450 4451 root.getChildren().add(child); 4452 return root; 4453 }; 4454 4455 final TreeItem<String> root = new TreeItem<String>(); 4456 root.setExpanded(true); 4457 root.getChildren().addAll(callback.call(1), callback.call(2)); 4458 4459 final TreeTableView<String> treeTableView = new TreeTableView<>(root); 4460 treeTableView.setShowRoot(false); 4461 4462 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4463 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4464 treeTableView.getColumns().add(column); 4465 4466 MultipleSelectionModel<TreeItem<String>> sm = treeTableView.getSelectionModel(); 4467 sm.getSelectedIndices().addListener((ListChangeListener<Integer>) c -> rt_38341_indices_count++); 4468 sm.getSelectedItems().addListener((ListChangeListener<TreeItem<String>>) c -> rt_38341_items_count++); 4469 4470 assertEquals(0, rt_38341_indices_count); 4471 assertEquals(0, rt_38341_items_count); 4472 4473 // expand the first child of root, and select it (note: root isn't visible) 4474 root.getChildren().get(0).setExpanded(true); 4475 sm.select(1); 4476 assertEquals(1, sm.getSelectedIndex()); 4477 assertEquals(1, sm.getSelectedIndices().size()); 4478 assertEquals(1, (int)sm.getSelectedIndices().get(0)); 4479 assertEquals(1, sm.getSelectedItems().size()); 4480 assertEquals("Child 1", sm.getSelectedItem().getValue()); 4481 assertEquals("Child 1", sm.getSelectedItems().get(0).getValue()); 4482 4483 assertEquals(1, rt_38341_indices_count); 4484 assertEquals(1, rt_38341_items_count); 4485 4486 // now delete it 4487 root.getChildren().get(0).getChildren().remove(0); 4488 4489 // selection should move to the childs parent in index 0 4490 assertEquals(0, sm.getSelectedIndex()); 4491 assertEquals(1, sm.getSelectedIndices().size()); 4492 assertEquals(0, (int)sm.getSelectedIndices().get(0)); 4493 assertEquals(1, sm.getSelectedItems().size()); 4494 assertEquals("Root 1", sm.getSelectedItem().getValue()); 4495 assertEquals("Root 1", sm.getSelectedItems().get(0).getValue()); 4496 4497 // we also expect there to be an event in the selection model for 4498 // selected indices and selected items 4499 assertEquals(2, rt_38341_indices_count); 4500 assertEquals(2, rt_38341_items_count); 4501 } 4502 4503 private int rt_38943_index_count = 0; 4504 private int rt_38943_item_count = 0; 4505 @Test public void test_rt_38943() { 4506 TreeItem<String> root = new TreeItem<>("Root"); 4507 root.setExpanded(true); 4508 root.getChildren().addAll( 4509 new TreeItem<>("a"), 4510 new TreeItem<>("b"), 4511 new TreeItem<>("c"), 4512 new TreeItem<>("d") 4513 ); 4514 4515 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4516 stringTreeTableView.setShowRoot(false); 4517 4518 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4519 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4520 stringTreeTableView.getColumns().add(column); 4521 4522 MultipleSelectionModel<TreeItem<String>> sm = stringTreeTableView.getSelectionModel(); 4523 4524 sm.selectedIndexProperty().addListener((observable, oldValue, newValue) -> rt_38943_index_count++); 4525 sm.selectedItemProperty().addListener((observable, oldValue, newValue) -> rt_38943_item_count++); 4526 4527 assertEquals(-1, sm.getSelectedIndex()); 4528 assertNull(sm.getSelectedItem()); 4529 assertEquals(0, rt_38943_index_count); 4530 assertEquals(0, rt_38943_item_count); 4531 4532 sm.select(0); 4533 assertEquals(0, sm.getSelectedIndex()); 4534 assertEquals("a", sm.getSelectedItem().getValue()); 4535 assertEquals(1, rt_38943_index_count); 4536 assertEquals(1, rt_38943_item_count); 4537 4538 sm.clearSelection(0); 4539 assertEquals(-1, sm.getSelectedIndex()); 4540 assertNull(sm.getSelectedItem()); 4541 assertEquals(2, rt_38943_index_count); 4542 assertEquals(2, rt_38943_item_count); 4543 } 4544 4545 @Test public void test_rt_38884() { 4546 final TreeItem<String> root = new TreeItem<>("Root"); 4547 final TreeItem<String> foo = new TreeItem<>("foo"); 4548 4549 TreeTableView<String> treeView = new TreeTableView<>(root); 4550 treeView.setShowRoot(false); 4551 root.setExpanded(true); 4552 4553 treeView.getSelectionModel().getSelectedItems().addListener((ListChangeListener.Change<? extends TreeItem<String>> c) -> { 4554 while (c.next()) { 4555 if (c.wasRemoved()) { 4556 assertTrue(c.getRemovedSize() > 0); 4557 4558 List<? extends TreeItem<String>> removed = c.getRemoved(); 4559 TreeItem<String> removedItem = null; 4560 try { 4561 removedItem = removed.get(0); 4562 } catch (Exception e) { 4563 fail(); 4564 } 4565 4566 assertEquals(foo, removedItem); 4567 } 4568 } 4569 }); 4570 4571 root.getChildren().add(foo); 4572 treeView.getSelectionModel().select(0); 4573 root.getChildren().clear(); 4574 } 4575 4576 private int rt_37360_add_count = 0; 4577 private int rt_37360_remove_count = 0; 4578 @Test public void test_rt_37360() { 4579 TreeItem<String> root = new TreeItem<>("Root"); 4580 root.setExpanded(true); 4581 root.getChildren().addAll( 4582 new TreeItem<>("a"), 4583 new TreeItem<>("b") 4584 ); 4585 4586 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4587 stringTreeTableView.setShowRoot(false); 4588 4589 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4590 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4591 stringTreeTableView.getColumns().add(column); 4592 4593 MultipleSelectionModel<TreeItem<String>> sm = stringTreeTableView.getSelectionModel(); 4594 sm.setSelectionMode(SelectionMode.MULTIPLE); 4595 sm.getSelectedItems().addListener((ListChangeListener<TreeItem<String>>) c -> { 4596 while (c.next()) { 4597 if (c.wasAdded()) { 4598 rt_37360_add_count += c.getAddedSize(); 4599 } 4600 if (c.wasRemoved()) { 4601 rt_37360_remove_count += c.getRemovedSize(); 4602 } 4603 } 4604 }); 4605 4606 assertEquals(0, sm.getSelectedItems().size()); 4607 assertEquals(0, rt_37360_add_count); 4608 assertEquals(0, rt_37360_remove_count); 4609 4610 sm.select(0); 4611 assertEquals(1, sm.getSelectedItems().size()); 4612 assertEquals(1, rt_37360_add_count); 4613 assertEquals(0, rt_37360_remove_count); 4614 4615 sm.select(1); 4616 assertEquals(2, sm.getSelectedItems().size()); 4617 assertEquals(2, rt_37360_add_count); 4618 assertEquals(0, rt_37360_remove_count); 4619 4620 sm.clearAndSelect(1); 4621 assertEquals(1, sm.getSelectedItems().size()); 4622 assertEquals(2, rt_37360_add_count); 4623 assertEquals(1, rt_37360_remove_count); 4624 } 4625 4626 private int rt_37366_count = 0; 4627 @Test public void test_rt_37366() { 4628 final TreeItem<String> treeItem2 = new TreeItem<>("Item 2"); 4629 treeItem2.getChildren().addAll(new TreeItem<>("Item 21"), new TreeItem<>("Item 22")); 4630 4631 final TreeItem<String> root1 = new TreeItem<>("Root Node 1"); 4632 TreeItem<String> treeItem1 = new TreeItem<>("Item 1"); 4633 root1.getChildren().addAll(treeItem1, treeItem2, new TreeItem<>("Item 3")); 4634 root1.setExpanded(true); 4635 4636 final TreeItem<String> root2 = new TreeItem<>("Root Node 2"); 4637 4638 final TreeItem<String> hiddenRoot = new TreeItem<>("Hidden Root Node"); 4639 hiddenRoot.getChildren().add(root1); 4640 hiddenRoot.getChildren().add(root2); 4641 4642 final TreeTableView<String> treeView = new TreeTableView<>(hiddenRoot); 4643 treeView.setShowRoot(false); 4644 4645 AtomicInteger step = new AtomicInteger(); 4646 MultipleSelectionModel<TreeItem<String>> sm = treeView.getSelectionModel(); 4647 sm.setSelectionMode(SelectionMode.MULTIPLE); 4648 sm.getSelectedItems().addListener((ListChangeListener.Change<? extends TreeItem<String>> c) -> { 4649 switch (step.get()) { 4650 case 0: { 4651 // we expect treeItem1 to be the only item added 4652 while (c.next()) { 4653 assertFalse(c.wasRemoved()); 4654 assertTrue(c.wasAdded()); 4655 assertEquals(1, c.getAddedSize()); 4656 assertTrue(c.getAddedSubList().contains(treeItem1)); 4657 } 4658 break; 4659 } 4660 case 1: { 4661 // we expect treeItem2 to be the only item added 4662 while (c.next()) { 4663 assertFalse(c.wasRemoved()); 4664 assertTrue(c.wasAdded()); 4665 assertEquals(1, c.getAddedSize()); 4666 assertTrue(c.getAddedSubList().contains(treeItem2)); 4667 } 4668 break; 4669 } 4670 case 2: { 4671 // we expect treeItem1 and treeItem2 to be removed in one separate event, 4672 // and then we expect a separate event for root1 to be added. Therefore, 4673 // once the remove event is received, we will increment the step to test for 4674 // the addition 4675 boolean wasRemoved = false; 4676 while (c.next()) { 4677 if (c.wasAdded()) { 4678 fail("no addition expected yet"); 4679 } 4680 if (c.wasRemoved()) { 4681 assertTrue(c.getRemoved().containsAll(FXCollections.observableArrayList(treeItem1, treeItem2))); 4682 wasRemoved = true; 4683 } 4684 } 4685 if (!wasRemoved) { 4686 fail("Expected a remove operation"); 4687 } 4688 step.incrementAndGet(); 4689 break; 4690 } 4691 case 3: { 4692 boolean wasAdded = false; 4693 while (c.next()) { 4694 if (c.wasAdded()) { 4695 assertEquals(1, c.getAddedSize()); 4696 assertTrue(c.getAddedSubList().contains(root1)); 4697 wasAdded = true; 4698 } 4699 if (c.wasRemoved()) { 4700 fail("no removal expected now"); 4701 } 4702 } 4703 if (!wasAdded) { 4704 fail("Expected an add operation"); 4705 } 4706 break; 4707 } 4708 } 4709 rt_37366_count++; 4710 }); 4711 4712 assertEquals(0, rt_37366_count); 4713 4714 step.set(0); 4715 sm.select(1); // select "Item 1" 4716 assertEquals(1, rt_37366_count); 4717 assertFalse(sm.isSelected(0)); 4718 assertTrue(sm.isSelected(1)); 4719 assertFalse(sm.isSelected(2)); 4720 4721 step.set(1); 4722 sm.select(2); // select "Item 2" 4723 assertEquals(2, rt_37366_count); 4724 assertFalse(sm.isSelected(0)); 4725 assertTrue(sm.isSelected(1)); 4726 assertTrue(sm.isSelected(2)); 4727 4728 step.set(2); 4729 root1.setExpanded(false); // collapse "Root Node 1" and deselect the two children, moving selection up to "Root Node 1" 4730 assertEquals(4, rt_37366_count); 4731 assertTrue(sm.isSelected(0)); 4732 assertFalse(sm.isSelected(1)); 4733 assertFalse(sm.isSelected(2)); 4734 } 4735 4736 @Test public void test_rt_38491() { 4737 TreeItem<String> a; 4738 TreeItem<String> root = new TreeItem<>("Root"); 4739 root.setExpanded(true); 4740 root.getChildren().addAll( 4741 a = new TreeItem<>("a"), 4742 new TreeItem<>("b") 4743 ); 4744 4745 TreeTableView<String> stringTreeView = new TreeTableView<>(root); 4746 stringTreeView.setShowRoot(false); 4747 4748 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4749 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4750 stringTreeView.getColumns().add(column); 4751 4752 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeView.getSelectionModel(); 4753 sm.setSelectionMode(SelectionMode.MULTIPLE); 4754 4755 TreeTableViewFocusModel<String> fm = stringTreeView.getFocusModel(); 4756 4757 StageLoader sl = new StageLoader(stringTreeView); 4758 4759 // test pre-conditions 4760 assertTrue(sm.isEmpty()); 4761 assertEquals(a, fm.getFocusedItem()); 4762 assertEquals(0, fm.getFocusedIndex()); 4763 4764 // click on row 0 4765 // VirtualFlowTestUtils.clickOnRow(stringTreeView, 0); 4766 sm.select(0, column); 4767 assertTrue(sm.isSelected(0)); 4768 assertEquals(a, sm.getSelectedItem()); 4769 assertTrue(fm.isFocused(0)); 4770 assertEquals(a, fm.getFocusedItem()); 4771 assertEquals(0, fm.getFocusedIndex()); 4772 assertEquals(0, fm.getFocusedCell().getRow()); 4773 assertEquals(column, fm.getFocusedCell().getTableColumn()); 4774 4775 TreeTablePosition<String, ?> anchor = TreeTableCellBehavior.getAnchor(stringTreeView, null); 4776 assertNotNull(anchor); 4777 assertTrue(TreeTableCellBehavior.hasNonDefaultAnchor(stringTreeView)); 4778 assertEquals(0, anchor.getRow()); 4779 4780 // now add a new item at row 0. This has the effect of pushing down 4781 // the selected item into row 1. 4782 root.getChildren().add(0, new TreeItem("z")); 4783 4784 // The first bug was that selection and focus were not moving down to 4785 // be on row 1, so we test that now 4786 assertFalse(sm.isSelected(0)); 4787 assertFalse(fm.isFocused(0)); 4788 assertTrue(sm.isSelected(1)); 4789 assertEquals(a, sm.getSelectedItem()); 4790 assertTrue(fm.isFocused(1)); 4791 assertEquals(a, fm.getFocusedItem()); 4792 assertEquals(1, fm.getFocusedIndex()); 4793 assertEquals(1, fm.getFocusedCell().getRow()); 4794 assertEquals(column, fm.getFocusedCell().getTableColumn()); 4795 4796 // The second bug was that the anchor was not being pushed down as well 4797 // (when it should). 4798 anchor = TreeTableCellBehavior.getAnchor(stringTreeView, null); 4799 assertNotNull(anchor); 4800 assertTrue(TreeTableCellBehavior.hasNonDefaultAnchor(stringTreeView)); 4801 assertEquals(1, anchor.getRow()); 4802 assertEquals(column, anchor.getTableColumn()); 4803 4804 sl.dispose(); 4805 } 4806 4807 private final ObservableList<TreeItem<String>> rt_39256_list = FXCollections.observableArrayList(); 4808 @Test public void test_rt_39256() { 4809 TreeItem<String> root = new TreeItem<>("Root"); 4810 root.setExpanded(true); 4811 root.getChildren().addAll( 4812 new TreeItem<>("a"), 4813 new TreeItem<>("b"), 4814 new TreeItem<>("c"), 4815 new TreeItem<>("d") 4816 ); 4817 4818 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4819 stringTreeTableView.setShowRoot(false); 4820 4821 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4822 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4823 stringTreeTableView.getColumns().add(column); 4824 4825 MultipleSelectionModel<TreeItem<String>> sm = stringTreeTableView.getSelectionModel(); 4826 sm.setSelectionMode(SelectionMode.MULTIPLE); 4827 4828 // rt_39256_list.addListener((ListChangeListener<TreeItem<String>>) change -> { 4829 // while (change.next()) { 4830 // System.err.println("number of selected persons (in bound list): " + change.getList().size()); 4831 // } 4832 // }); 4833 4834 Bindings.bindContent(rt_39256_list, sm.getSelectedItems()); 4835 4836 assertEquals(0, sm.getSelectedItems().size()); 4837 assertEquals(0, rt_39256_list.size()); 4838 4839 sm.selectAll(); 4840 assertEquals(4, sm.getSelectedItems().size()); 4841 assertEquals(4, rt_39256_list.size()); 4842 4843 sm.selectAll(); 4844 assertEquals(4, sm.getSelectedItems().size()); 4845 assertEquals(4, rt_39256_list.size()); 4846 4847 sm.selectAll(); 4848 assertEquals(4, sm.getSelectedItems().size()); 4849 assertEquals(4, rt_39256_list.size()); 4850 } 4851 4852 private final ObservableList<TreeItem<String>> rt_39482_list = FXCollections.observableArrayList(); 4853 @Test public void test_rt_39482() { 4854 TreeItem<String> root = new TreeItem<>("Root"); 4855 root.setExpanded(true); 4856 root.getChildren().addAll( 4857 new TreeItem<>("a"), 4858 new TreeItem<>("b"), 4859 new TreeItem<>("c"), 4860 new TreeItem<>("d") 4861 ); 4862 4863 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4864 stringTreeTableView.setShowRoot(false); 4865 4866 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4867 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4868 stringTreeTableView.getColumns().add(column); 4869 4870 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 4871 sm.setSelectionMode(SelectionMode.MULTIPLE); 4872 4873 // rt_39256_list.addListener((ListChangeListener<TreeItem<String>>) change -> { 4874 // while (change.next()) { 4875 // System.err.println("number of selected persons (in bound list): " + change.getList().size()); 4876 // } 4877 // }); 4878 4879 Bindings.bindContent(rt_39482_list, sm.getSelectedItems()); 4880 4881 assertEquals(0, sm.getSelectedItems().size()); 4882 assertEquals(0, rt_39482_list.size()); 4883 4884 test_rt_39482_selectRow("a", sm, 0, column); 4885 test_rt_39482_selectRow("b", sm, 1, column); 4886 test_rt_39482_selectRow("c", sm, 2, column); 4887 test_rt_39482_selectRow("d", sm, 3, column); 4888 } 4889 4890 private void test_rt_39482_selectRow(String expectedString, 4891 TreeTableView.TreeTableViewSelectionModel<String> sm, 4892 int rowToSelect, 4893 TreeTableColumn<String,String> columnToSelect) { 4894 System.out.println("\nSelect row " + rowToSelect); 4895 sm.selectAll(); 4896 assertEquals(4, sm.getSelectedCells().size()); 4897 assertEquals(4, sm.getSelectedIndices().size()); 4898 assertEquals(4, sm.getSelectedItems().size()); 4899 assertEquals(4, rt_39482_list.size()); 4900 4901 sm.clearAndSelect(rowToSelect, columnToSelect); 4902 assertEquals(1, sm.getSelectedCells().size()); 4903 assertEquals(1, sm.getSelectedIndices().size()); 4904 assertEquals(1, sm.getSelectedItems().size()); 4905 assertEquals(expectedString, sm.getSelectedItem().getValue()); 4906 assertEquals(expectedString, rt_39482_list.get(0).getValue()); 4907 assertEquals(1, rt_39482_list.size()); 4908 } 4909 4910 @Test public void test_rt_39559_useSM_selectAll() { 4911 test_rt_39559(true); 4912 } 4913 4914 @Test public void test_rt_39559_useKeyboard_selectAll() { 4915 test_rt_39559(false); 4916 } 4917 4918 private void test_rt_39559(boolean useSMSelectAll) { 4919 TreeItem<String> a, b; 4920 TreeItem<String> root = new TreeItem<>("Root"); 4921 root.setExpanded(true); 4922 root.getChildren().addAll( 4923 a = new TreeItem<>("a"), 4924 b = new TreeItem<>("b"), 4925 new TreeItem<>("c"), 4926 new TreeItem<>("d") 4927 ); 4928 4929 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4930 stringTreeTableView.setShowRoot(false); 4931 4932 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4933 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4934 stringTreeTableView.getColumns().add(column); 4935 4936 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 4937 sm.setSelectionMode(SelectionMode.MULTIPLE); 4938 4939 StageLoader sl = new StageLoader(stringTreeTableView); 4940 KeyEventFirer keyboard = new KeyEventFirer(stringTreeTableView); 4941 4942 assertEquals(0, sm.getSelectedItems().size()); 4943 4944 sm.clearAndSelect(0); 4945 4946 if (useSMSelectAll) { 4947 sm.selectAll(); 4948 } else { 4949 keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey()); 4950 } 4951 4952 assertEquals(4, sm.getSelectedItems().size()); 4953 assertEquals(0, ((TreeTablePosition) TreeTableCellBehavior.getAnchor(stringTreeTableView, null)).getRow()); 4954 4955 keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); 4956 4957 assertEquals(0, ((TreeTablePosition) TreeTableCellBehavior.getAnchor(stringTreeTableView, null)).getRow()); 4958 assertEquals(2, sm.getSelectedItems().size()); 4959 assertEquals(a, sm.getSelectedItems().get(0)); 4960 assertEquals(b, sm.getSelectedItems().get(1)); 4961 4962 sl.dispose(); 4963 } 4964 4965 @Test public void test_rt_16068_firstElement_selectAndRemoveSameRow() { 4966 // select and then remove the 'a' item, selection and focus should both 4967 // stay at the first row, now 'b' 4968 test_rt_16068(0, 0, 0); 4969 } 4970 4971 @Test public void test_rt_16068_firstElement_selectRowAndRemoveLaterSibling() { 4972 // select row 'a', and remove row 'c', selection and focus should not change 4973 test_rt_16068(0, 2, 0); 4974 } 4975 4976 @Test public void test_rt_16068_middleElement_selectAndRemoveSameRow() { 4977 // select and then remove the 'b' item, selection and focus should both 4978 // move up one row to the 'a' item 4979 test_rt_16068(1, 1, 0); 4980 } 4981 4982 @Test public void test_rt_16068_middleElement_selectRowAndRemoveLaterSibling() { 4983 // select row 'b', and remove row 'c', selection and focus should not change 4984 test_rt_16068(1, 2, 1); 4985 } 4986 4987 @Test public void test_rt_16068_middleElement_selectRowAndRemoveEarlierSibling() { 4988 // select row 'b', and remove row 'a', selection and focus should move up 4989 // one row, remaining on 'b' 4990 test_rt_16068(1, 0, 0); 4991 } 4992 4993 @Test public void test_rt_16068_lastElement_selectAndRemoveSameRow() { 4994 // select and then remove the 'd' item, selection and focus should both 4995 // move up one row to the 'c' item 4996 test_rt_16068(3, 3, 2); 4997 } 4998 4999 @Test public void test_rt_16068_lastElement_selectRowAndRemoveEarlierSibling() { 5000 // select row 'd', and remove row 'a', selection and focus should move up 5001 // one row, remaining on 'd' 5002 test_rt_16068(3, 0, 2); 5003 } 5004 5005 private void test_rt_16068(int indexToSelect, int indexToRemove, int expectedIndex) { 5006 TreeItem<String> root = new TreeItem<>("Root"); 5007 root.setExpanded(true); 5008 root.getChildren().addAll( 5009 new TreeItem<>("a"), // 0 5010 new TreeItem<>("b"), // 1 5011 new TreeItem<>("c"), // 2 5012 new TreeItem<>("d") // 3 5013 ); 5014 5015 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5016 stringTreeTableView.setShowRoot(false); 5017 5018 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5019 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5020 stringTreeTableView.getColumns().add(column); 5021 5022 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 5023 FocusModel<TreeItem<String>> fm = stringTreeTableView.getFocusModel(); 5024 5025 sm.select(indexToSelect); 5026 assertEquals(indexToSelect, sm.getSelectedIndex()); 5027 assertEquals(root.getChildren().get(indexToSelect).getValue(), sm.getSelectedItem().getValue()); 5028 assertEquals(indexToSelect, fm.getFocusedIndex()); 5029 assertEquals(root.getChildren().get(indexToSelect).getValue(), fm.getFocusedItem().getValue()); 5030 5031 root.getChildren().remove(indexToRemove); 5032 assertEquals(expectedIndex, sm.getSelectedIndex()); 5033 assertEquals(root.getChildren().get(expectedIndex).getValue(), sm.getSelectedItem().getValue()); 5034 assertEquals(debug(), expectedIndex, fm.getFocusedIndex()); 5035 assertEquals(root.getChildren().get(expectedIndex).getValue(), fm.getFocusedItem().getValue()); 5036 } 5037 5038 @Test public void test_rt_39675() { 5039 TreeItem<String> b; 5040 TreeItem<String> root = new TreeItem<>("Root"); 5041 root.setExpanded(true); 5042 root.getChildren().addAll( 5043 new TreeItem<>("a"), 5044 b = new TreeItem<>("b"), 5045 new TreeItem<>("c"), 5046 new TreeItem<>("d") 5047 ); 5048 5049 b.setExpanded(true); 5050 b.getChildren().addAll( 5051 new TreeItem<>("b1"), 5052 new TreeItem<>("b2"), 5053 new TreeItem<>("b3"), 5054 new TreeItem<>("b4") 5055 ); 5056 5057 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5058 5059 TreeTableColumn<String,String> column0 = new TreeTableColumn<>("Column1"); 5060 column0.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5061 5062 TreeTableColumn<String,String> column1 = new TreeTableColumn<>("Column2"); 5063 column1.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5064 5065 TreeTableColumn<String,String> column2 = new TreeTableColumn<>("Column3"); 5066 column2.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5067 5068 stringTreeTableView.getColumns().addAll(column0, column1, column2); 5069 5070 sm = stringTreeTableView.getSelectionModel(); 5071 sm.setSelectionMode(SelectionMode.SINGLE); 5072 sm.setCellSelectionEnabled(true); 5073 5074 StageLoader sl = new StageLoader(stringTreeTableView); 5075 5076 assertEquals(0, sm.getSelectedItems().size()); 5077 5078 sm.clearAndSelect(4, column0); // select 'b2' in row 4, column 0 5079 assertTrue(sm.isSelected(4, column0)); 5080 assertEquals(1, sm.getSelectedCells().size()); 5081 assertEquals("b2", ((TreeItem)sm.getSelectedItem()).getValue()); 5082 5083 // collapse the 'b' tree item, selection and focus should go to 5084 // the 'b' tree item in row 2, column 0 5085 b.setExpanded(false); 5086 assertTrue(sm.isSelected(2, column0)); 5087 assertEquals(1, sm.getSelectedCells().size()); 5088 assertEquals("b", ((TreeItem)sm.getSelectedItem()).getValue()); 5089 5090 sl.dispose(); 5091 } 5092 5093 5094 private ObservableList<String> test_rt_39661_setup() { 5095 ObservableList<String> rawItems = FXCollections.observableArrayList( 5096 "9-item", "8-item", "7-item", "6-item", 5097 "5-item", "4-item", "3-item", "2-item", "1-item"); 5098 root = createSubTree("root", rawItems); 5099 root.setExpanded(true); 5100 treeTableView = new TreeTableView(root); 5101 return rawItems; 5102 } 5103 5104 private TreeItem createSubTree(Object item, ObservableList<String> rawItems) { 5105 TreeItem child = new TreeItem(item); 5106 child.getChildren().setAll(rawItems.stream() 5107 .map(rawItem -> new TreeItem(rawItem)) 5108 .collect(Collectors.toList())); 5109 return child; 5110 } 5111 5112 @Test public void test_rt_39661_rowLessThanExpandedItemCount() { 5113 ObservableList<String> rawItems = test_rt_39661_setup(); 5114 TreeItem child = createSubTree("child", rawItems); 5115 TreeItem grandChild = (TreeItem) child.getChildren().get(rawItems.size() - 1); 5116 root.getChildren().add(child); 5117 assertTrue("row of item must be less than expandedItemCount, but was: " + treeTableView.getRow(grandChild), 5118 treeTableView.getRow(grandChild) < treeTableView.getExpandedItemCount()); 5119 } 5120 5121 @Test public void test_rt_39661_rowOfGrandChildParentCollapsedUpdatedOnInsertAbove() { 5122 ObservableList<String> rawItems = test_rt_39661_setup(); 5123 int grandIndex = 2; 5124 int childIndex = 3; 5125 5126 TreeItem child = createSubTree("addedChild2", rawItems); 5127 TreeItem grandChild = (TreeItem) child.getChildren().get(grandIndex); 5128 root.getChildren().add(childIndex, child); 5129 5130 int rowOfGrand = treeTableView.getRow(grandChild); 5131 root.getChildren().add(childIndex - 1, createSubTree("other", rawItems)); 5132 5133 assertEquals(-1, treeTableView.getRow(grandChild)); 5134 } 5135 5136 @Test public void test_rt_39661_rowOfGrandChildParentCollapsedUpdatedOnInsertAboveWithoutAccess() { 5137 ObservableList<String> rawItems = test_rt_39661_setup(); 5138 int grandIndex = 2; 5139 int childIndex = 3; 5140 5141 TreeItem child = createSubTree("addedChild2", rawItems); 5142 TreeItem grandChild = (TreeItem) child.getChildren().get(grandIndex); 5143 root.getChildren().add(childIndex, child); 5144 5145 int rowOfGrand = 7; //treeTableView.getRow(grandChild); 5146 root.getChildren().add(childIndex, createSubTree("other", rawItems)); 5147 5148 assertEquals(-1, treeTableView.getRow(grandChild)); 5149 } 5150 5151 @Test public void test_rt_39661_rowOfGrandChildParentExpandedUpdatedOnInsertAbove() { 5152 ObservableList<String> rawItems = test_rt_39661_setup(); 5153 int grandIndex = 2; 5154 int childIndex = 3; 5155 TreeItem child = createSubTree("addedChild2", rawItems); 5156 TreeItem grandChild = (TreeItem) child.getChildren().get(grandIndex); 5157 child.setExpanded(true); 5158 root.getChildren().add(childIndex, child); 5159 int rowOfGrand = treeTableView.getRow(grandChild); 5160 root.getChildren().add(childIndex -1, createSubTree("other", rawItems)); 5161 assertEquals(rowOfGrand + 1, treeTableView.getRow(grandChild)); 5162 } 5163 5164 /** 5165 * Testing getRow on grandChild: compare collapsed/expanded parent. 5166 */ 5167 @Test public void test_rt_39661_rowOfGrandChildDependsOnParentExpansion() { 5168 ObservableList<String> rawItems = test_rt_39661_setup(); 5169 int grandIndex = 2; 5170 int childIndex = 3; 5171 5172 TreeItem collapsedChild = createSubTree("addedChild", rawItems); 5173 TreeItem collapsedGrandChild = (TreeItem) collapsedChild.getChildren().get(grandIndex); 5174 root.getChildren().add(childIndex, collapsedChild); 5175 5176 int collapedGrandIndex = treeTableView.getRow(collapsedGrandChild); 5177 int collapsedRowCount = treeTableView.getExpandedItemCount(); 5178 5179 // start again 5180 test_rt_39661_setup(); 5181 assertEquals(collapsedRowCount - 1, treeTableView.getExpandedItemCount()); 5182 TreeItem expandedChild = createSubTree("addedChild2", rawItems); 5183 TreeItem expandedGrandChild = (TreeItem) expandedChild.getChildren().get(grandIndex); 5184 expandedChild.setExpanded(true); 5185 5186 root.getChildren().add(childIndex, expandedChild); 5187 assertNotSame("getRow must depend on expansionState " + collapedGrandIndex, 5188 collapedGrandIndex, treeTableView.getRow(expandedGrandChild)); 5189 } 5190 5191 @Test public void test_rt_39661_rowOfGrandChildInCollapsedChild() { 5192 ObservableList<String> rawItems = test_rt_39661_setup(); 5193 5194 // create a collapsed new child to insert into the root 5195 TreeItem newChild = createSubTree("added-child", rawItems); 5196 TreeItem grandChild = (TreeItem) newChild.getChildren().get(2); 5197 root.getChildren().add(6, newChild); 5198 5199 // query the row of a grand-child 5200 int row = treeTableView.getRow(grandChild); 5201 5202 // grandChild not visible, row coordinate in tree is not available 5203 assertEquals("grandChild not visible", -1, row); 5204 5205 // the other way round: if we get a row, expect the item at the row be the grandChild 5206 if (row > -1) { 5207 assertEquals(grandChild, treeTableView.getTreeItem(row)); 5208 } 5209 } 5210 5211 @Test public void test_rt_39661_rowOfRootChild() { 5212 ObservableList<String> rawItems = test_rt_39661_setup(); 5213 int index = 2; 5214 5215 TreeItem child = (TreeItem) root.getChildren().get(index); 5216 assertEquals(index + 1, treeTableView.getRow(child)); 5217 } 5218 5219 @Test public void test_rt_39661_expandedItemCount() { 5220 ObservableList<String> rawItems = test_rt_39661_setup(); 5221 int initialRowCount = treeTableView.getExpandedItemCount(); 5222 assertEquals(root.getChildren().size() + 1, initialRowCount); 5223 5224 TreeItem collapsedChild = createSubTree("collapsed-child", rawItems); 5225 root.getChildren().add(collapsedChild); 5226 assertEquals(initialRowCount + 1, treeTableView.getExpandedItemCount()); 5227 5228 TreeItem expandedChild = createSubTree("expanded-child", rawItems); 5229 expandedChild.setExpanded(true); 5230 root.getChildren().add(0, expandedChild); 5231 assertEquals(2 * initialRowCount + 1, treeTableView.getExpandedItemCount()); 5232 } 5233 5234 private int test_rt_39822_count = 0; 5235 @Test public void test_rt_39822() { 5236 // get the current exception handler before replacing with our own, 5237 // as ListListenerHelp intercepts the exception otherwise 5238 final Thread.UncaughtExceptionHandler exceptionHandler = Thread.currentThread().getUncaughtExceptionHandler(); 5239 Thread.currentThread().setUncaughtExceptionHandler((t, e) -> { 5240 e.printStackTrace(); 5241 5242 if (test_rt_39822_count == 0) { 5243 test_rt_39822_count++; 5244 if (! (e instanceof IllegalStateException)) { 5245 fail("Incorrect exception type - expecting IllegalStateException"); 5246 } 5247 } else { 5248 // don't care 5249 test_rt_39822_count++; 5250 } 5251 }); 5252 5253 TreeTableView<String> table = new TreeTableView<>(); 5254 TreeTableColumn<String, String> col1 = new TreeTableColumn<>("Foo"); 5255 table.getColumns().addAll(col1, col1); // add column twice 5256 5257 StageLoader sl = null; 5258 try { 5259 sl = new StageLoader(table); 5260 } finally { 5261 if (sl != null) { 5262 sl.dispose(); 5263 } 5264 5265 // reset the exception handler 5266 Thread.currentThread().setUncaughtExceptionHandler(exceptionHandler); 5267 } 5268 } 5269 5270 private int test_rt_39842_count = 0; 5271 @Test public void test_rt_39842_selectLeftDown() { 5272 test_rt_39842(true, false); 5273 } 5274 5275 @Test public void test_rt_39842_selectLeftUp() { 5276 test_rt_39842(true, true); 5277 } 5278 5279 @Test public void test_rt_39842_selectRightDown() { 5280 test_rt_39842(false, false); 5281 } 5282 5283 @Test public void test_rt_39842_selectRightUp() { 5284 test_rt_39842(false, true); 5285 } 5286 5287 private void test_rt_39842(boolean selectToLeft, boolean selectUpwards) { 5288 test_rt_39842_count = 0; 5289 5290 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 5291 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 5292 5293 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 5294 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 5295 5296 TreeItem root = new TreeItem("root"); 5297 root.getChildren().setAll( 5298 new TreeItem(new Person("Jacob", "Smith", "jacob.smith@example.com")), 5299 new TreeItem(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 5300 new TreeItem(new Person("Ethan", "Williams", "ethan.williams@example.com")), 5301 new TreeItem(new Person("Emma", "Jones", "emma.jones@example.com")), 5302 new TreeItem(new Person("Michael", "Brown", "michael.brown@example.com"))); 5303 root.setExpanded(true); 5304 5305 TreeTableView<Person> table = new TreeTableView<>(root); 5306 table.setShowRoot(false); 5307 table.getColumns().addAll(firstNameCol, lastNameCol); 5308 5309 sm = table.getSelectionModel(); 5310 sm.setCellSelectionEnabled(true); 5311 sm.setSelectionMode(SelectionMode.MULTIPLE); 5312 sm.getSelectedCells().addListener((ListChangeListener) c -> test_rt_39842_count++); 5313 5314 StageLoader sl = new StageLoader(table); 5315 5316 assertEquals(0, test_rt_39842_count); 5317 5318 if (selectToLeft) { 5319 if (selectUpwards) { 5320 sm.selectRange(3, lastNameCol, 0, firstNameCol); 5321 } else { 5322 sm.selectRange(0, lastNameCol, 3, firstNameCol); 5323 } 5324 } else { 5325 if (selectUpwards) { 5326 sm.selectRange(3, firstNameCol, 0, lastNameCol); 5327 } else { 5328 sm.selectRange(0, firstNameCol, 3, lastNameCol); 5329 } 5330 } 5331 5332 // test model state 5333 assertEquals(8, sm.getSelectedCells().size()); 5334 assertEquals(1, test_rt_39842_count); 5335 5336 // test visual state 5337 for (int row = 0; row <= 3; row++) { 5338 for (int column = 0; column <= 1; column++) { 5339 IndexedCell cell = VirtualFlowTestUtils.getCell(table, row, column); 5340 assertTrue(cell.isSelected()); 5341 } 5342 } 5343 5344 sl.dispose(); 5345 } 5346 5347 @Test public void test_rt_22599() { 5348 TreeItem<RT22599_DataType> root = new TreeItem<>(); 5349 root.getChildren().setAll( 5350 new TreeItem<>(new RT22599_DataType(1, "row1")), 5351 new TreeItem<>(new RT22599_DataType(2, "row2")), 5352 new TreeItem<>(new RT22599_DataType(3, "row3"))); 5353 root.setExpanded(true); 5354 5355 TreeTableColumn<RT22599_DataType, String> col = new TreeTableColumn<>("Header"); 5356 col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue().text)); 5357 5358 TreeTableView<RT22599_DataType> table = new TreeTableView<>(root); 5359 table.setShowRoot(false); 5360 table.getColumns().addAll(col); 5361 5362 StageLoader sl = new StageLoader(table); 5363 5364 // testing initial state 5365 assertNotNull(table.getSkin()); 5366 assertEquals("row1", VirtualFlowTestUtils.getCell(table, 0, 0).getText()); 5367 assertEquals("row2", VirtualFlowTestUtils.getCell(table, 1, 0).getText()); 5368 assertEquals("row3", VirtualFlowTestUtils.getCell(table, 2, 0).getText()); 5369 5370 // change row 0 (where "row1" currently resides), keeping same id. 5371 // Because 'set' is called, the control should update to the new content 5372 // without any user interaction 5373 TreeItem<RT22599_DataType> data; 5374 root.getChildren().set(0, data = new TreeItem<>(new RT22599_DataType(0, "row1a"))); 5375 Toolkit.getToolkit().firePulse(); 5376 assertEquals("row1a", VirtualFlowTestUtils.getCell(table, 0, 0).getText()); 5377 5378 // change the row 0 (where we currently have "row1a") value directly. 5379 // Because there is no associated property, this won't be observed, so 5380 // the control should still show "row1a" rather than "row1b" 5381 data.getValue().text = "row1b"; 5382 Toolkit.getToolkit().firePulse(); 5383 assertEquals("row1a", VirtualFlowTestUtils.getCell(table, 0, 0).getText()); 5384 5385 // call refresh() to force a refresh of all visible cells 5386 table.refresh(); 5387 Toolkit.getToolkit().firePulse(); 5388 assertEquals("row1b", VirtualFlowTestUtils.getCell(table, 0, 0).getText()); 5389 5390 sl.dispose(); 5391 } 5392 5393 private static class RT22599_DataType { 5394 public int id = 0; 5395 public String text = ""; 5396 5397 public RT22599_DataType(int id, String text) { 5398 this.id = id; 5399 this.text = text; 5400 } 5401 5402 @Override public boolean equals(Object obj) { 5403 if (obj == null) return false; 5404 return id == ((RT22599_DataType)obj).id; 5405 } 5406 } 5407 5408 private int rt_39966_count = 0; 5409 @Test public void test_rt_39966() { 5410 TreeItem<String> root = new TreeItem<>("Root"); 5411 TreeTableView<String> table = new TreeTableView<>(root); 5412 table.setShowRoot(true); 5413 5414 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5415 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5416 table.getColumns().add(column); 5417 5418 StageLoader sl = new StageLoader(table); 5419 5420 // initially there is no selection 5421 assertTrue(table.getSelectionModel().isEmpty()); 5422 5423 table.getSelectionModel().selectedItemProperty().addListener((value, s1, s2) -> { 5424 if (rt_39966_count == 0) { 5425 rt_39966_count++; 5426 assertFalse(table.getSelectionModel().isEmpty()); 5427 } else { 5428 assertTrue(table.getSelectionModel().isEmpty()); 5429 } 5430 }); 5431 5432 // our assertion two lines down always succeeds. What fails is our 5433 // assertion above within the listener. 5434 table.getSelectionModel().select(0); 5435 assertFalse(table.getSelectionModel().isEmpty()); 5436 5437 table.setRoot(null); 5438 assertTrue(table.getSelectionModel().isEmpty()); 5439 5440 sl.dispose(); 5441 } 5442 5443 /** 5444 * Bullet 1: selected index must be updated 5445 * Corner case: last selected. Fails for core 5446 */ 5447 @Test public void test_rt_40012_selectedAtLastOnDisjointRemoveItemsAbove() { 5448 TreeItem<String> root = new TreeItem<>("Root"); 5449 root.setExpanded(true); 5450 root.getChildren().addAll( 5451 new TreeItem<>("0"), 5452 new TreeItem<>("1"), 5453 new TreeItem<>("2"), 5454 new TreeItem<>("3"), 5455 new TreeItem<>("4"), 5456 new TreeItem<>("5") 5457 ); 5458 5459 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5460 stringTreeTableView.setShowRoot(false); 5461 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 5462 5463 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5464 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5465 stringTreeTableView.getColumns().add(column); 5466 5467 int last = root.getChildren().size() - 1; 5468 5469 // selecting item "5" 5470 sm.select(last); 5471 5472 // disjoint remove of 2 elements above the last selected 5473 // Removing "1" and "3" 5474 root.getChildren().removeAll(root.getChildren().get(1), root.getChildren().get(3)); 5475 5476 // selection should move up two places such that it remains on item "5", 5477 // but in index (last - 2). 5478 int expected = last - 2; 5479 assertEquals("5", sm.getSelectedItem().getValue()); 5480 assertEquals("selected index after disjoint removes above", expected, sm.getSelectedIndex()); 5481 } 5482 5483 /** 5484 * Variant of 1: if selectedIndex is not updated, 5485 * the old index is no longer valid 5486 * for accessing the items. 5487 */ 5488 @Test public void test_rt_40012_accessSelectedAtLastOnDisjointRemoveItemsAbove() { 5489 TreeItem<String> root = new TreeItem<>("Root"); 5490 root.setExpanded(true); 5491 root.getChildren().addAll( 5492 new TreeItem<>("0"), 5493 new TreeItem<>("1"), 5494 new TreeItem<>("2"), 5495 new TreeItem<>("3"), 5496 new TreeItem<>("4"), 5497 new TreeItem<>("5") 5498 ); 5499 5500 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5501 stringTreeTableView.setShowRoot(false); 5502 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 5503 5504 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5505 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5506 stringTreeTableView.getColumns().add(column); 5507 5508 int last = root.getChildren().size() - 1; 5509 5510 // selecting item "5" 5511 sm.select(last); 5512 5513 // disjoint remove of 2 elements above the last selected 5514 root.getChildren().removeAll(root.getChildren().get(1), root.getChildren().get(3)); 5515 int selected = sm.getSelectedIndex(); 5516 if (selected > -1) { 5517 root.getChildren().get(selected); 5518 } 5519 } 5520 5521 /** 5522 * Bullet 2: selectedIndex notification count 5523 * 5524 * Note that we don't use the corner case of having the last index selected 5525 * (which fails already on updating the index) 5526 */ 5527 private int rt_40012_count = 0; 5528 @Test public void test_rt_40012_selectedIndexNotificationOnDisjointRemovesAbove() { 5529 TreeItem<String> root = new TreeItem<>("Root"); 5530 root.setExpanded(true); 5531 root.getChildren().addAll( 5532 new TreeItem<>("0"), 5533 new TreeItem<>("1"), 5534 new TreeItem<>("2"), 5535 new TreeItem<>("3"), 5536 new TreeItem<>("4"), 5537 new TreeItem<>("5") 5538 ); 5539 5540 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5541 stringTreeTableView.setShowRoot(false); 5542 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 5543 5544 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5545 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5546 stringTreeTableView.getColumns().add(column); 5547 5548 int last = root.getChildren().size() - 2; 5549 sm.select(last); 5550 assertEquals(last, sm.getSelectedIndex()); 5551 5552 rt_40012_count = 0; 5553 sm.selectedIndexProperty().addListener(o -> rt_40012_count++); 5554 5555 // disjoint remove of 2 elements above the last selected 5556 root.getChildren().removeAll(root.getChildren().get(1), root.getChildren().get(3)); 5557 assertEquals("sanity: selectedIndex must be shifted by -2", last - 2, sm.getSelectedIndex()); 5558 assertEquals("must fire single event on removes above", 1, rt_40012_count); 5559 } 5560 5561 /** 5562 * Bullet 3: unchanged selectedItem must not fire change 5563 */ 5564 @Test 5565 public void test_rt_40012_selectedItemNotificationOnDisjointRemovesAbove() { 5566 TreeItem<String> root = new TreeItem<>("Root"); 5567 root.setExpanded(true); 5568 root.getChildren().addAll( 5569 new TreeItem<>("0"), 5570 new TreeItem<>("1"), 5571 new TreeItem<>("2"), 5572 new TreeItem<>("3"), 5573 new TreeItem<>("4"), 5574 new TreeItem<>("5") 5575 ); 5576 5577 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5578 stringTreeTableView.setShowRoot(false); 5579 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 5580 5581 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5582 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5583 stringTreeTableView.getColumns().add(column); 5584 5585 int last = root.getChildren().size() - 2; 5586 Object lastItem = root.getChildren().get(last); 5587 sm.select(last); 5588 assertEquals(lastItem, sm.getSelectedItem()); 5589 5590 rt_40012_count = 0; 5591 sm.selectedItemProperty().addListener(o -> rt_40012_count++); 5592 5593 // disjoint remove of 2 elements above the last selected 5594 root.getChildren().removeAll(root.getChildren().get(1), root.getChildren().get(3)); 5595 assertEquals("sanity: selectedItem unchanged", lastItem, sm.getSelectedItem()); 5596 assertEquals("must not fire on unchanged selected item", 0, rt_40012_count); 5597 } 5598 5599 private int rt_40010_count = 0; 5600 @Test public void test_rt_40010() { 5601 TreeItem<String> root = new TreeItem<>("Root"); 5602 TreeItem<String> child = new TreeItem<>("child"); 5603 root.setExpanded(true); 5604 root.getChildren().addAll(child); 5605 5606 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5607 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 5608 5609 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5610 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5611 stringTreeTableView.getColumns().add(column); 5612 5613 sm.getSelectedIndices().addListener((ListChangeListener<? super Integer>) l -> rt_40010_count++); 5614 sm.getSelectedItems().addListener((ListChangeListener<? super TreeItem<String>>) l -> rt_40010_count++); 5615 5616 assertEquals(0, rt_40010_count); 5617 5618 sm.select(1); 5619 assertEquals(1, sm.getSelectedIndex()); 5620 assertEquals(child, sm.getSelectedItem()); 5621 assertEquals(2, rt_40010_count); 5622 5623 root.getChildren().remove(child); 5624 assertEquals(0, sm.getSelectedIndex()); 5625 assertEquals(root, sm.getSelectedItem()); 5626 assertEquals(4, rt_40010_count); 5627 } 5628 5629 /** 5630 * ClearAndSelect fires invalid change event if selectedIndex is unchanged. 5631 */ 5632 private int rt_40212_count = 0; 5633 @Test public void test_rt_40212() { 5634 TreeItem<String> root = new TreeItem<>("Root"); 5635 root.setExpanded(true); 5636 root.getChildren().addAll( 5637 new TreeItem<>("0"), 5638 new TreeItem<>("1"), 5639 new TreeItem<>("2"), 5640 new TreeItem<>("3"), 5641 new TreeItem<>("4"), 5642 new TreeItem<>("5") 5643 ); 5644 5645 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5646 stringTreeTableView.setShowRoot(false); 5647 5648 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 5649 sm.setSelectionMode(SelectionMode.MULTIPLE); 5650 5651 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5652 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5653 stringTreeTableView.getColumns().add(column); 5654 5655 sm.selectRange(3, 5); 5656 int selected = sm.getSelectedIndex(); 5657 5658 sm.getSelectedIndices().addListener((ListChangeListener<Integer>) change -> { 5659 assertEquals("sanity: selectedIndex unchanged", selected, sm.getSelectedIndex()); 5660 while(change.next()) { 5661 assertEquals("single event on clearAndSelect already selected", 1, ++rt_40212_count); 5662 5663 boolean type = change.wasAdded() || change.wasRemoved() || change.wasPermutated() || change.wasUpdated(); 5664 assertTrue("at least one of the change types must be true", type); 5665 } 5666 }); 5667 5668 sm.clearAndSelect(selected); 5669 } 5670 5671 @Test public void test_rt_40280() { 5672 final TreeTableView<String> view = new TreeTableView<>(); 5673 StageLoader sl = new StageLoader(view); 5674 MultipleSelectionModelBaseShim.getFocusedIndex(view.getSelectionModel()); 5675 view.getFocusModel().getFocusedIndex(); 5676 sl.dispose(); 5677 } 5678 5679 @Test public void test_rt_40278_showRoot() { 5680 TreeItem<String> root = new TreeItem<>("Root"); 5681 root.setExpanded(true); 5682 root.getChildren().addAll(new TreeItem<>("0"),new TreeItem<>("1")); 5683 5684 TreeTableView<String> view = new TreeTableView<>(root); 5685 view.setShowRoot(false); 5686 MultipleSelectionModel<TreeItem<String>> sm = view.getSelectionModel(); 5687 5688 assertFalse("sanity: test setup such that root is not showing", view.isShowRoot()); 5689 sm.select(0); 5690 assertEquals(0, sm.getSelectedIndex()); 5691 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 5692 view.setShowRoot(true); 5693 assertEquals(1, sm.getSelectedIndex()); 5694 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 5695 } 5696 5697 @Test public void test_rt_40278_hideRoot_selectionOnChild() { 5698 TreeItem<String> root = new TreeItem<>("Root"); 5699 root.setExpanded(true); 5700 root.getChildren().addAll(new TreeItem<>("0"),new TreeItem<>("1")); 5701 5702 TreeTableView<String> view = new TreeTableView<>(root); 5703 view.setShowRoot(true); 5704 MultipleSelectionModel<TreeItem<String>> sm = view.getSelectionModel(); 5705 5706 assertTrue("sanity: test setup such that root is showing", view.isShowRoot()); 5707 sm.select(1); 5708 assertEquals(1, sm.getSelectedIndex()); 5709 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 5710 view.setShowRoot(false); 5711 assertEquals(0, sm.getSelectedIndex()); 5712 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 5713 } 5714 5715 @Test public void test_rt_40278_hideRoot_selectionOnRoot() { 5716 TreeItem<String> root = new TreeItem<>("Root"); 5717 root.setExpanded(true); 5718 root.getChildren().addAll(new TreeItem<>("0"),new TreeItem<>("1")); 5719 5720 TreeTableView<String> view = new TreeTableView<>(root); 5721 view.setShowRoot(true); 5722 MultipleSelectionModel<TreeItem<String>> sm = view.getSelectionModel(); 5723 5724 assertTrue("sanity: test setup such that root is showing", view.isShowRoot()); 5725 sm.select(0); 5726 assertEquals(0, sm.getSelectedIndex()); 5727 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 5728 view.setShowRoot(false); 5729 assertEquals(0, sm.getSelectedIndex()); 5730 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 5731 } 5732 5733 /** 5734 * Test list change of selectedIndices on setIndices. Fails for core .. 5735 */ 5736 @Test public void test_rt_40263() { 5737 TreeItem<Integer> root = new TreeItem<>(-1); 5738 root.setExpanded(true); 5739 5740 for (int i = 0; i < 10; i++) { 5741 root.getChildren().add(new TreeItem<Integer>(i)); 5742 } 5743 5744 final TreeTableView<Integer> view = new TreeTableView<>(root); 5745 TreeTableView.TreeTableViewSelectionModel<Integer> sm = view.getSelectionModel(); 5746 sm.setSelectionMode(SelectionMode.MULTIPLE); 5747 5748 int[] indices = new int[]{2, 5, 7}; 5749 ListChangeListener<Integer> l = c -> { 5750 // firstly, we expect only one change 5751 int subChanges = 0; 5752 while(c.next()) { 5753 subChanges++; 5754 } 5755 assertEquals(1, subChanges); 5756 5757 // secondly, we expect the added size to be three, as that is the 5758 // number of items selected 5759 c.reset(); 5760 c.next(); 5761 System.out.println("Added items: " + c.getAddedSubList()); 5762 assertEquals(indices.length, c.getAddedSize()); 5763 assertArrayEquals(indices, c.getAddedSubList().stream().mapToInt(i -> i).toArray()); 5764 }; 5765 sm.getSelectedIndices().addListener(l); 5766 sm.selectIndices(indices[0], indices); 5767 } 5768 5769 @Test public void test_rt_40319_toRight_toBottom() { test_rt_40319(true, true, false); } 5770 @Test public void test_rt_40319_toRight_toTop() { test_rt_40319(true, false, false); } 5771 @Test public void test_rt_40319_toLeft_toBottom() { test_rt_40319(false, true, false); } 5772 @Test public void test_rt_40319_toLeft_toTop() { test_rt_40319(false, false, false); } 5773 @Test public void test_rt_40319_toRight_toBottom_useMouse() { test_rt_40319(true, true, true); } 5774 @Test public void test_rt_40319_toRight_toTop_useMouse() { test_rt_40319(true, false, true); } 5775 @Test public void test_rt_40319_toLeft_toBottom_useMouse() { test_rt_40319(false, true, true); } 5776 @Test public void test_rt_40319_toLeft_toTop_useMouse() { test_rt_40319(false, false, true); } 5777 5778 private void test_rt_40319(boolean toRight, boolean toBottom, boolean useMouse) { 5779 TreeItem<String> root = new TreeItem<>("Root"); 5780 root.setExpanded(true); 5781 root.getChildren().addAll( 5782 new TreeItem<>("0"), 5783 new TreeItem<>("1"), 5784 new TreeItem<>("2"), 5785 new TreeItem<>("3"), 5786 new TreeItem<>("4"), 5787 new TreeItem<>("5") 5788 ); 5789 5790 TreeTableView<String> t = new TreeTableView<>(root); 5791 t.setShowRoot(false); 5792 5793 sm = t.getSelectionModel(); 5794 sm.setSelectionMode(SelectionMode.MULTIPLE); 5795 5796 TreeTableColumn<String,String> c1 = new TreeTableColumn<>("Column"); 5797 c1.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5798 TreeTableColumn<String,String> c2 = new TreeTableColumn<>("Column"); 5799 c2.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5800 t.getColumns().addAll(c1, c2); 5801 5802 final int startIndex = toRight ? 0 : 2; 5803 final int endIndex = toRight ? 2 : 0; 5804 final TreeTableColumn<String,String> startColumn = toBottom ? c1 : c2; 5805 final TreeTableColumn<String,String> endColumn = toBottom ? c2 : c1; 5806 5807 sm.select(startIndex, startColumn); 5808 5809 if (useMouse) { 5810 Cell endCell = VirtualFlowTestUtils.getCell(t, endIndex, toRight ? 1 : 0); 5811 MouseEventFirer mouse = new MouseEventFirer(endCell); 5812 mouse.fireMousePressAndRelease(KeyModifier.SHIFT); 5813 } else { 5814 t.getSelectionModel().selectRange(startIndex, startColumn, endIndex, endColumn); 5815 } 5816 5817 assertEquals(3, sm.getSelectedItems().size()); 5818 assertEquals(3, sm.getSelectedIndices().size()); 5819 assertEquals(3, sm.getSelectedCells().size()); 5820 } 5821 5822 @Test public void test_jdk_8147483() { 5823 TreeItem<Number> root = new TreeItem<>(0); 5824 root.setExpanded(true); 5825 5826 final TreeTableView<Number> view = new TreeTableView<>(root); 5827 view.setShowRoot(false); 5828 5829 AtomicInteger cellUpdateCount = new AtomicInteger(); 5830 AtomicInteger rowCreateCount = new AtomicInteger(); 5831 5832 TreeTableColumn<Number, Number> column = new TreeTableColumn<>("Column"); 5833 column.setCellValueFactory(cdf -> new ReadOnlyIntegerWrapper(0)); 5834 column.setCellFactory( ttc -> new TreeTableCell<Number,Number>() { 5835 @Override protected void updateItem(Number item, boolean empty) { 5836 cellUpdateCount.incrementAndGet(); 5837 super.updateItem(item, empty); 5838 } 5839 }); 5840 view.getColumns().add(column); 5841 5842 view.setRowFactory(t -> { 5843 rowCreateCount.incrementAndGet(); 5844 return new TreeTableRow<>(); 5845 }); 5846 5847 assertEquals(0, cellUpdateCount.get()); 5848 assertEquals(0, rowCreateCount.get()); 5849 5850 StageLoader sl = new StageLoader(view); 5851 5852 // Before the fix, we got cellUpdateCount = 18 and rowCreateCount = 17 for the first add below. 5853 // After the second add, these numbers went to 53 and 17 respectively. 5854 // Because these numbers might differ on other systems, we simply record the values after 5855 // the first add, and then we expect the cellUpdateCount to increase by one, and rowCreateCount to 5856 // not increase at all. 5857 root.getChildren().add(new TreeItem(1)); 5858 Toolkit.getToolkit().firePulse(); 5859 final int firstCellUpdateCount = cellUpdateCount.get(); 5860 final int firstRowCreateCount = rowCreateCount.get(); 5861 5862 root.getChildren().add(new TreeItem(2)); 5863 Toolkit.getToolkit().firePulse(); 5864 assertEquals(firstCellUpdateCount+1, cellUpdateCount.get()); 5865 assertEquals(firstRowCreateCount, rowCreateCount.get()); 5866 5867 root.getChildren().add(new TreeItem(3)); 5868 Toolkit.getToolkit().firePulse(); 5869 assertEquals(firstCellUpdateCount+2, cellUpdateCount.get()); 5870 assertEquals(firstRowCreateCount, rowCreateCount.get()); 5871 5872 sl.dispose(); 5873 } 5874 5875 @Test public void test_jdk_8144681_removeColumn() { 5876 TreeTableView<Book> table = new TreeTableView<>(); 5877 5878 TreeItem<Book> root = new TreeItem<>(); 5879 root.getChildren().addAll( 5880 new TreeItem<>(new Book("Book 1", "Author 1", "Remark 1")) 5881 , new TreeItem<>(new Book("Book 2", "Author 2", "Remark 2")) 5882 , new TreeItem<>(new Book("Book 3", "Author 3", "Remark 3")) 5883 , new TreeItem<>(new Book("Book 4", "Author 4", "Remark 4"))); 5884 table.setRoot(root); 5885 5886 String[] columns = { "title", "author", "remark" }; 5887 for (String prop : columns) { 5888 TreeTableColumn<Book, String> col = new TreeTableColumn<>(prop); 5889 col.setCellValueFactory(new TreeItemPropertyValueFactory<>(prop)); 5890 table.getColumns().add(col); 5891 } 5892 table.setColumnResizePolicy(TreeTableView.UNCONSTRAINED_RESIZE_POLICY); 5893 table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 5894 table.getSelectionModel().setCellSelectionEnabled(true); 5895 5896 table.getSelectionModel().selectAll(); 5897 5898 ControlTestUtils.runWithExceptionHandler(() -> table.getColumns().remove(2)); 5899 } 5900 5901 @Test public void test_jdk_8144681_moveColumn() { 5902 TreeTableView<Book> table = new TreeTableView<>(); 5903 5904 TreeItem<Book> root = new TreeItem<>(); 5905 root.getChildren().addAll( 5906 new TreeItem<>(new Book("Book 1", "Author 1", "Remark 1")) 5907 , new TreeItem<>(new Book("Book 2", "Author 2", "Remark 2")) 5908 , new TreeItem<>(new Book("Book 3", "Author 3", "Remark 3")) 5909 , new TreeItem<>(new Book("Book 4", "Author 4", "Remark 4"))); 5910 table.setRoot(root); 5911 5912 String[] columns = { "title", "author", "remark" }; 5913 for (String prop : columns) { 5914 TreeTableColumn<Book, String> col = new TreeTableColumn<>(prop); 5915 col.setCellValueFactory(new TreeItemPropertyValueFactory<>(prop)); 5916 table.getColumns().add(col); 5917 } 5918 table.setColumnResizePolicy(TreeTableView.UNCONSTRAINED_RESIZE_POLICY); 5919 table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 5920 table.getSelectionModel().setCellSelectionEnabled(true); 5921 5922 table.getSelectionModel().selectAll(); 5923 5924 ControlTestUtils.runWithExceptionHandler(() -> { 5925 table.getColumns().setAll(table.getColumns().get(0), table.getColumns().get(2), table.getColumns().get(1)); 5926 }); 5927 } 5928 5929 private static class Book { 5930 private SimpleStringProperty title = new SimpleStringProperty(); 5931 private SimpleStringProperty author = new SimpleStringProperty(); 5932 private SimpleStringProperty remark = new SimpleStringProperty(); 5933 5934 public Book(String title, String author, String remark) { 5935 super(); 5936 setTitle(title); 5937 setAuthor(author); 5938 setRemark(remark); 5939 } 5940 5941 public SimpleStringProperty titleProperty() { 5942 return this.title; 5943 } 5944 5945 public java.lang.String getTitle() { 5946 return this.titleProperty().get(); 5947 } 5948 5949 public void setTitle(final java.lang.String title) { 5950 this.titleProperty().set(title); 5951 } 5952 5953 public SimpleStringProperty authorProperty() { 5954 return this.author; 5955 } 5956 5957 public java.lang.String getAuthor() { 5958 return this.authorProperty().get(); 5959 } 5960 5961 public void setAuthor(final java.lang.String author) { 5962 this.authorProperty().set(author); 5963 } 5964 5965 public SimpleStringProperty remarkProperty() { 5966 return this.remark; 5967 } 5968 5969 public java.lang.String getRemark() { 5970 return this.remarkProperty().get(); 5971 } 5972 5973 public void setRemark(final java.lang.String remark) { 5974 this.remarkProperty().set(remark); 5975 } 5976 5977 @Override 5978 public String toString() { 5979 return String.format("%s(%s) - %s", getTitle(), getAuthor(), getRemark()); 5980 } 5981 } 5982 5983 @Test public void test_jdk_8157205() { 5984 final TreeItem<String> childNode1 = new TreeItem<>("Child Node 1"); 5985 childNode1.setExpanded(true); 5986 TreeItem<String> item1 = new TreeItem<>("Node 1-1"); 5987 TreeItem<String> item2 = new TreeItem<>("Node 1-2"); 5988 childNode1.getChildren().addAll(item1, item2); 5989 5990 final TreeItem<String> root = new TreeItem<>("Root node"); 5991 root.setExpanded(true); 5992 root.getChildren().add(childNode1); 5993 5994 final TreeTableView<String> view = new TreeTableView<>(root); 5995 MultipleSelectionModel<TreeItem<String>> sm = view.getSelectionModel(); 5996 sm.setSelectionMode(SelectionMode.MULTIPLE); 5997 5998 AtomicInteger step = new AtomicInteger(); 5999 6000 AtomicInteger indicesEventCount = new AtomicInteger(); 6001 sm.getSelectedIndices().addListener((ListChangeListener<Integer>)c -> { 6002 switch (step.get()) { 6003 case 0: { 6004 // expect to see [1,2,3] added at index 0 6005 c.next(); 6006 assertEquals(3, c.getAddedSize()); 6007 assertTrue("added: " + c.getAddedSubList(), 6008 c.getAddedSubList().containsAll(FXCollections.observableArrayList(1,2,3))); 6009 assertEquals(0, c.getFrom()); 6010 break; 6011 } 6012 case 1: { 6013 // expect to see [2,3] removed 6014 List<Integer> removed = new ArrayList<>(); 6015 while (c.next()) { 6016 if (c.wasRemoved()) { 6017 removed.addAll(c.getRemoved()); 6018 } else { 6019 fail("Unexpected state"); 6020 } 6021 } 6022 if (!removed.isEmpty()) { 6023 assertTrue(removed.containsAll(FXCollections.observableArrayList(2,3))); 6024 } 6025 break; 6026 } 6027 } 6028 6029 indicesEventCount.incrementAndGet(); 6030 }); 6031 6032 AtomicInteger itemsEventCount = new AtomicInteger(); 6033 sm.getSelectedItems().addListener((ListChangeListener<TreeItem<String>>)c -> { 6034 switch (step.get()) { 6035 case 0: { 6036 // expect to see [1,2,3] added at index 0 6037 c.next(); 6038 assertEquals(3, c.getAddedSize()); 6039 assertTrue("added: " + c.getAddedSubList(), 6040 c.getAddedSubList().containsAll(FXCollections.observableArrayList(childNode1, item1, item2))); 6041 assertEquals(0, c.getFrom()); 6042 break; 6043 } 6044 case 1: { 6045 // expect to see [2,3] removed 6046 List<TreeItem<String>> removed = new ArrayList<>(); 6047 while (c.next()) { 6048 if (c.wasRemoved()) { 6049 removed.addAll(c.getRemoved()); 6050 } else { 6051 fail("Unexpected state"); 6052 } 6053 } 6054 if (!removed.isEmpty()) { 6055 assertTrue(removed.containsAll(FXCollections.observableArrayList(item1, item2))); 6056 } 6057 break; 6058 } 6059 } 6060 6061 itemsEventCount.incrementAndGet(); 6062 }); 6063 6064 assertEquals(0, indicesEventCount.get()); 6065 assertEquals(0, itemsEventCount.get()); 6066 6067 step.set(0); 6068 sm.selectIndices(1,2,3); // select Child Node 1 and both children 6069 assertTrue(sm.isSelected(1)); 6070 assertTrue(sm.isSelected(2)); 6071 assertTrue(sm.isSelected(3)); 6072 assertEquals(3, sm.getSelectedIndices().size()); 6073 assertEquals(3, sm.getSelectedItems().size()); 6074 assertEquals(1, indicesEventCount.get()); 6075 assertEquals(1, itemsEventCount.get()); 6076 6077 step.set(1); 6078 System.out.println("about to collapse now"); 6079 childNode1.setExpanded(false); // collapse Child Node 1 and expect both children to be deselected 6080 assertTrue(sm.isSelected(1)); 6081 assertFalse(sm.isSelected(2)); 6082 assertFalse(sm.isSelected(3)); 6083 assertEquals(1, sm.getSelectedIndices().size()); 6084 assertEquals(1, sm.getSelectedItems().size()); 6085 assertEquals(2, indicesEventCount.get()); 6086 assertEquals(2, itemsEventCount.get()); 6087 6088 step.set(2); 6089 childNode1.setExpanded(true); // expand Child Node 1 and expect both children to still be deselected 6090 assertTrue(sm.isSelected(1)); 6091 assertFalse(sm.isSelected(2)); 6092 assertFalse(sm.isSelected(3)); 6093 assertEquals(1, sm.getSelectedIndices().size()); 6094 assertEquals(1, sm.getSelectedItems().size()); 6095 assertEquals(2, indicesEventCount.get()); 6096 assertEquals(2, itemsEventCount.get()); 6097 } 6098 6099 @Test public void test_jdk_8157285() { 6100 final TreeItem<String> childNode1 = new TreeItem<>("Child Node 1"); 6101 childNode1.setExpanded(true); 6102 TreeItem<String> item1 = new TreeItem<>("Node 1-1"); 6103 TreeItem<String> item2 = new TreeItem<>("Node 1-2"); 6104 childNode1.getChildren().addAll(item1, item2); 6105 6106 final TreeItem<String> root = new TreeItem<>("Root node"); 6107 root.setExpanded(true); 6108 root.getChildren().add(childNode1); 6109 6110 final TreeTableView<String> view = new TreeTableView<>(root); 6111 MultipleSelectionModel<TreeItem<String>> sm = view.getSelectionModel(); 6112 sm.setSelectionMode(SelectionMode.MULTIPLE); 6113 6114 view.expandedItemCountProperty().addListener((observable, oldCount, newCount) -> { 6115 if (childNode1.isExpanded()) return; 6116 System.out.println(sm.getSelectedIndices()); 6117 System.out.println(sm.getSelectedItems()); 6118 assertTrue(sm.isSelected(1)); 6119 assertFalse(sm.isSelected(2)); 6120 assertFalse(sm.isSelected(3)); 6121 assertEquals(1, sm.getSelectedIndices().size()); 6122 assertEquals(1, sm.getSelectedItems().size()); 6123 }); 6124 6125 sm.selectIndices(1,2,3); // select Child Node 1 and both children 6126 assertTrue(sm.isSelected(1)); 6127 assertTrue(sm.isSelected(2)); 6128 assertTrue(sm.isSelected(3)); 6129 assertEquals(3, sm.getSelectedIndices().size()); 6130 assertEquals(3, sm.getSelectedItems().size()); 6131 6132 // collapse Child Node 1 and expect both children to be deselected, 6133 // and that in the expandedItemCount listener that we get the right values 6134 // in the selectedIndices and selectedItems list 6135 childNode1.setExpanded(false); 6136 } 6137 6138 @Test public void test_jdk_8152396() { 6139 final TreeItem<String> childNode1 = new TreeItem<>("Child Node 1"); 6140 TreeItem<String> item1 = new TreeItem<>("Node 1-1"); 6141 TreeItem<String> item2 = new TreeItem<>("Node 1-2"); 6142 childNode1.getChildren().addAll(item1, item2); 6143 6144 final TreeItem<String> root = new TreeItem<>("Root node"); 6145 root.setExpanded(true); 6146 root.getChildren().add(childNode1); 6147 6148 final TreeTableView<String> view = new TreeTableView<>(root); 6149 MultipleSelectionModel<TreeItem<String>> sm = view.getSelectionModel(); 6150 sm.setSelectionMode(SelectionMode.MULTIPLE); 6151 6152 view.expandedItemCountProperty().addListener((observable, oldCount, newCount) -> { 6153 if (newCount.intValue() > oldCount.intValue()) { 6154 for (int index: sm.getSelectedIndices()) { 6155 TreeItem<String> item = view.getTreeItem(index); 6156 6157 if (item != null && item.isExpanded() && !item.getChildren().isEmpty()) { 6158 int startIndex = index + 1; 6159 int maxCount = startIndex + item.getChildren().size(); 6160 6161 sm.selectRange(startIndex, maxCount); 6162 } 6163 } 6164 } 6165 }); 6166 6167 FilteredList filteredList = sm.getSelectedItems().filtered(Objects::nonNull); 6168 6169 StageLoader sl = new StageLoader(view); 6170 6171 sm.select(1); 6172 childNode1.setExpanded(true); 6173 Toolkit.getToolkit().firePulse(); 6174 6175 // collapse Child Node 1 and expect both children to be deselected, 6176 // and that the filtered list does not throw an exception 6177 assertEquals(3, filteredList.size()); 6178 ControlTestUtils.runWithExceptionHandler(() -> childNode1.setExpanded(false)); 6179 6180 Toolkit.getToolkit().firePulse(); 6181 assertEquals(1, filteredList.size()); 6182 6183 sl.dispose(); 6184 } 6185 }