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