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 StageLoader sl = new StageLoader(table); 3658 3659 ControlTestUtils.runWithExceptionHandler(() -> { 3660 table.getSelectionModel().select(0); 3661 table.getSortOrder().add(nameColumn); 3662 }); 3663 3664 sl.dispose(); 3665 } 3666 3667 private int rt_37429_items_change_count = 0; 3668 private int rt_37429_cells_change_count = 0; 3669 @Test public void test_rt_37429_sortEventsShouldNotFireExtraChangeEvents() { 3670 // table items - 3 items, 2nd item has 2 children 3671 TreeItem<String> root = new TreeItem<>(); 3672 3673 root.getChildren().add(new TreeItem<>("a")); 3674 root.getChildren().add(new TreeItem<>("c")); 3675 root.getChildren().add(new TreeItem<>("b")); 3676 3677 // table columns - 1 column; name 3678 TreeTableColumn<String, String> nameColumn = new TreeTableColumn<>("name"); 3679 nameColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper(param.getValue().getValue())); 3680 nameColumn.setPrefWidth(200); 3681 3682 // table 3683 TreeTableView<String> table = new TreeTableView<>(); 3684 table.setShowRoot(false); 3685 table.setRoot(root); 3686 table.getColumns().addAll(nameColumn); 3687 3688 table.getSelectionModel().getSelectedItems().addListener((ListChangeListener<TreeItem<String>>) c -> { 3689 while (c.next()) { 3690 rt_37429_items_change_count++; 3691 } 3692 }); 3693 table.getSelectionModel().getSelectedCells().addListener((ListChangeListener<TreeTablePosition<String, ?>>) c -> { 3694 while (c.next()) { 3695 rt_37429_cells_change_count++; 3696 } 3697 }); 3698 3699 StageLoader sl = new StageLoader(table); 3700 3701 assertEquals(0, rt_37429_items_change_count); 3702 assertEquals(0, rt_37429_cells_change_count); 3703 3704 table.getSelectionModel().select(0); 3705 assertEquals(1, rt_37429_items_change_count); 3706 assertEquals(1, rt_37429_cells_change_count); 3707 3708 table.getSortOrder().add(nameColumn); 3709 assertEquals(1, rt_37429_items_change_count); 3710 assertEquals(1, rt_37429_cells_change_count); 3711 3712 nameColumn.setSortType(TreeTableColumn.SortType.DESCENDING); 3713 assertEquals(1, rt_37429_items_change_count); 3714 assertEquals(2, rt_37429_cells_change_count); 3715 3716 nameColumn.setSortType(TreeTableColumn.SortType.ASCENDING); 3717 assertEquals(1, rt_37429_items_change_count); 3718 assertEquals(3, rt_37429_cells_change_count); 3719 3720 sl.dispose(); 3721 } 3722 3723 private int rt_37538_count = 0; 3724 @Test public void test_rt_37538_noCNextCall() { 3725 test_rt_37538(false, false); 3726 } 3727 3728 @Test public void test_rt_37538_callCNextOnce() { 3729 test_rt_37538(true, false); 3730 } 3731 3732 @Test public void test_rt_37538_callCNextInLoop() { 3733 test_rt_37538(false, true); 3734 } 3735 3736 private void test_rt_37538(boolean callCNextOnce, boolean callCNextInLoop) { 3737 // create table with a bunch of rows and 1 column... 3738 TreeItem<Integer> root = new TreeItem<>(0); 3739 root.setExpanded(true); 3740 for (int i = 1; i <= 50; i++) { 3741 root.getChildren().add(new TreeItem<>(i)); 3742 } 3743 3744 final TreeTableColumn<Integer, Integer> column = new TreeTableColumn<>("Column"); 3745 column.setCellValueFactory( cdf -> new ReadOnlyObjectWrapper<Integer>(cdf.getValue().getValue())); 3746 3747 final TreeTableView<Integer> table = new TreeTableView<>(root); 3748 table.getColumns().add( column ); 3749 3750 table.getSelectionModel().getSelectedItems().addListener((ListChangeListener.Change<? extends TreeItem<Integer>> c) -> { 3751 if (callCNextOnce) { 3752 c.next(); 3753 } else if (callCNextInLoop) { 3754 while (c.next()) { 3755 // no-op 3756 } 3757 } 3758 3759 if (rt_37538_count >= 1) { 3760 Thread.dumpStack(); 3761 fail("This method should only be called once"); 3762 } 3763 3764 rt_37538_count++; 3765 }); 3766 3767 StageLoader sl = new StageLoader(table); 3768 assertEquals(0, rt_37538_count); 3769 table.getSelectionModel().select(0); 3770 assertEquals(1, rt_37538_count); 3771 sl.dispose(); 3772 } 3773 3774 @Test public void test_rt_37593() { 3775 TreeItem<String> root = new TreeItem<>(); 3776 3777 TreeItem<String> one = new TreeItem<>("one"); 3778 root.getChildren().add(one); 3779 3780 TreeItem<String> two = new TreeItem<>("two"); 3781 two.getChildren().add(new TreeItem<>("childOne")); 3782 two.getChildren().add(new TreeItem<>("childTwo")); 3783 root.getChildren().add(two); 3784 3785 root.getChildren().add(new TreeItem<>("three")); 3786 3787 TreeTableColumn<String, String> nameColumn = new TreeTableColumn<>("name"); 3788 nameColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper(param.getValue().getValue())); 3789 3790 treeTableView.setShowRoot(false); 3791 treeTableView.setRoot(root); 3792 treeTableView.getColumns().addAll(nameColumn); 3793 3794 treeTableView.getSortOrder().add(nameColumn); 3795 nameColumn.setSortType(TreeTableColumn.SortType.DESCENDING); 3796 sm.select(one); 3797 3798 // at this point, the 'one' item should be in row 2 3799 assertTrue(sm.isSelected(2)); 3800 assertEquals(one, sm.getSelectedItem()); 3801 3802 two.setExpanded(true); 3803 3804 // we should end up with the selection being on index 4, which is the 3805 // final location of the 'one' tree item, after sorting and expanding 'two' 3806 assertEquals(one, sm.getSelectedItem()); 3807 assertTrue(debug(), sm.isSelected(4)); 3808 3809 // this line would create a NPE 3810 VirtualFlowTestUtils.clickOnRow(treeTableView, 4, true); 3811 3812 // The mouse click should not change selection at all 3813 assertEquals(one, sm.getSelectedItem()); 3814 assertTrue(debug(), sm.isSelected(4)); 3815 } 3816 3817 @Test public void test_rt_35395_testCell_fixedCellSize() { 3818 test_rt_35395(true, true); 3819 } 3820 3821 @Test public void test_rt_35395_testCell_notFixedCellSize() { 3822 test_rt_35395(true, false); 3823 } 3824 3825 @Ignore("Fix not yet developed for TreeTableView") 3826 @Test public void test_rt_35395_testRow_fixedCellSize() { 3827 test_rt_35395(false, true); 3828 } 3829 3830 @Ignore("Fix not yet developed for TreeTableView") 3831 @Test public void test_rt_35395_testRow_notFixedCellSize() { 3832 test_rt_35395(false, false); 3833 } 3834 3835 private int rt_35395_counter; 3836 private void test_rt_35395(boolean testCell, boolean useFixedCellSize) { 3837 rt_35395_counter = 0; 3838 3839 TreeItem<String> root = new TreeItem<>("green"); 3840 root.setExpanded(true); 3841 for (int i = 0; i < 20; i++) { 3842 root.getChildren().addAll(new TreeItem<>("red"), new TreeItem<>("green"), new TreeItem<>("blue"), new TreeItem<>("purple")); 3843 } 3844 3845 TreeTableView<String> treeTableView = new TreeTableView<>(root); 3846 if (useFixedCellSize) { 3847 treeTableView.setFixedCellSize(24); 3848 } 3849 treeTableView.setRowFactory(tv -> new TreeTableRow<String>() { 3850 @Override protected void updateItem(String color, boolean empty) { 3851 rt_35395_counter += testCell ? 0 : 1; 3852 super.updateItem(color, empty); 3853 } 3854 }); 3855 3856 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 3857 column.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue())); 3858 column.setCellFactory(tv -> new TreeTableCell<String,String>() { 3859 @Override protected void updateItem(String color, boolean empty) { 3860 rt_35395_counter += testCell ? 1 : 0; 3861 super.updateItem(color, empty); 3862 setText(null); 3863 if (empty) { 3864 setGraphic(null); 3865 } else { 3866 Rectangle rect = new Rectangle(16, 16); 3867 rect.setStyle("-fx-fill: " + color); 3868 setGraphic(rect); 3869 } 3870 } 3871 }); 3872 treeTableView.getColumns().addAll(column); 3873 3874 StageLoader sl = new StageLoader(treeTableView); 3875 3876 Platform.runLater(() -> { 3877 rt_35395_counter = 0; 3878 root.getChildren().set(10, new TreeItem<>("yellow")); 3879 Platform.runLater(() -> { 3880 Toolkit.getToolkit().firePulse(); 3881 assertEquals(1, rt_35395_counter); 3882 rt_35395_counter = 0; 3883 root.getChildren().set(30, new TreeItem<>("yellow")); 3884 Platform.runLater(() -> { 3885 Toolkit.getToolkit().firePulse(); 3886 assertEquals(0, rt_35395_counter); 3887 rt_35395_counter = 0; 3888 treeTableView.scrollTo(5); 3889 Platform.runLater(() -> { 3890 Toolkit.getToolkit().firePulse(); 3891 assertEquals(useFixedCellSize ? 2 : 5, rt_35395_counter); 3892 rt_35395_counter = 0; 3893 treeTableView.scrollTo(55); 3894 Platform.runLater(() -> { 3895 Toolkit.getToolkit().firePulse(); 3896 3897 assertEquals(useFixedCellSize ? 9 : 59, rt_35395_counter); 3898 sl.dispose(); 3899 }); 3900 }); 3901 }); 3902 }); 3903 }); 3904 } 3905 3906 @Test public void test_rt_37632() { 3907 final TreeItem<String> rootOne = new TreeItem<>("Root 1"); 3908 final TreeItem<String> rootTwo = new TreeItem<>("Root 2"); 3909 3910 TreeTableColumn<String,String> tableColumn = new TreeTableColumn("column"); 3911 tableColumn.setCellValueFactory(c -> new ReadOnlyStringWrapper(c.getValue().getValue())); 3912 3913 final TreeTableView<String> treeTableView = new TreeTableView<>(); 3914 treeTableView.getColumns().addAll(tableColumn); 3915 MultipleSelectionModel<TreeItem<String>> sm = treeTableView.getSelectionModel(); 3916 treeTableView.setRoot(rootOne); 3917 treeTableView.getSelectionModel().selectFirst(); 3918 3919 assertEquals(0, sm.getSelectedIndex()); 3920 assertEquals(rootOne, sm.getSelectedItem()); 3921 assertEquals(1, sm.getSelectedIndices().size()); 3922 assertEquals(0, (int) sm.getSelectedIndices().get(0)); 3923 assertEquals(1, sm.getSelectedItems().size()); 3924 assertEquals(rootOne, sm.getSelectedItems().get(0)); 3925 3926 treeTableView.setRoot(rootTwo); 3927 3928 assertEquals(-1, sm.getSelectedIndex()); 3929 assertNull(sm.getSelectedItem()); 3930 assertEquals(0, sm.getSelectedIndices().size()); 3931 assertEquals(0, sm.getSelectedItems().size()); 3932 } 3933 3934 private TreeTableView<Person> test_rt_38464_createControl() { 3935 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 3936 new TreeItem<>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 3937 new TreeItem<>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 3938 new TreeItem<>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 3939 new TreeItem<>(new Person("Emma", "Jones", "emma.jones@example.com")), 3940 new TreeItem<>(new Person("Michael", "Brown", "michael.brown@example.com"))); 3941 3942 TreeTableView<Person> table = new TreeTableView<>(); 3943 table.setShowRoot(false); 3944 3945 TreeItem<Person> root = new TreeItem<>(new Person("Root", null, null)); 3946 root.setExpanded(true); 3947 root.getChildren().setAll(persons); 3948 table.setRoot(root); 3949 3950 3951 3952 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 3953 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 3954 3955 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 3956 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 3957 3958 table.getColumns().addAll(firstNameCol, lastNameCol); 3959 3960 return table; 3961 } 3962 3963 @Test public void test_rt_38464_rowSelection_selectFirstRowOnly() { 3964 TreeTableView<Person> table = test_rt_38464_createControl(); 3965 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 3966 sm.setCellSelectionEnabled(false); 3967 sm.setSelectionMode(SelectionMode.MULTIPLE); 3968 3969 sm.select(0); 3970 3971 assertTrue(sm.isSelected(0)); 3972 assertTrue(sm.isSelected(0, table.getColumns().get(0))); 3973 assertTrue(sm.isSelected(0, table.getColumns().get(1))); 3974 3975 assertEquals(1, sm.getSelectedIndices().size()); 3976 assertEquals(1, sm.getSelectedItems().size()); 3977 assertEquals(1, sm.getSelectedCells().size()); 3978 } 3979 3980 @Test public void test_rt_38464_rowSelection_selectFirstRowAndThenCallNoOpMethods() { 3981 TreeTableView<Person> table = test_rt_38464_createControl(); 3982 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 3983 sm.setCellSelectionEnabled(false); 3984 sm.setSelectionMode(SelectionMode.MULTIPLE); 3985 3986 sm.select(0); // select first row 3987 sm.select(0); // this should be a no-op 3988 sm.select(0, table.getColumns().get(0)); // so should this, as we are in row selection mode 3989 sm.select(0, table.getColumns().get(1)); // and same here 3990 3991 assertTrue(sm.isSelected(0)); 3992 assertTrue(sm.isSelected(0, table.getColumns().get(0))); 3993 assertTrue(sm.isSelected(0, table.getColumns().get(1))); 3994 3995 assertEquals(1, sm.getSelectedIndices().size()); 3996 assertEquals(1, sm.getSelectedItems().size()); 3997 assertEquals(1, sm.getSelectedCells().size()); 3998 } 3999 4000 4001 @Test public void test_rt_38464_cellSelection_selectFirstRowOnly() { 4002 TreeTableView<Person> table = test_rt_38464_createControl(); 4003 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 4004 sm.setCellSelectionEnabled(true); 4005 sm.setSelectionMode(SelectionMode.MULTIPLE); 4006 4007 // select first row. This should be translated into selection of all 4008 // cells in this row, but does not result in the row itself being 4009 // considered selected. 4010 sm.select(0); 4011 4012 assertFalse(sm.isSelected(0)); 4013 assertTrue(sm.isSelected(0, table.getColumns().get(0))); 4014 assertTrue(sm.isSelected(0, table.getColumns().get(1))); 4015 4016 assertEquals(1, sm.getSelectedIndices().size()); 4017 assertEquals(1, sm.getSelectedItems().size()); 4018 assertEquals(2, sm.getSelectedCells().size()); 4019 } 4020 4021 @Test public void test_rt_38464_cellSelection_selectFirstRowAndThenCallNoOpMethods() { 4022 TreeTableView<Person> table = test_rt_38464_createControl(); 4023 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 4024 sm.setCellSelectionEnabled(true); 4025 sm.setSelectionMode(SelectionMode.MULTIPLE); 4026 4027 // select first row. This should be translated into selection of all 4028 // cells in this row, but does not result in the row itself being 4029 // considered selected. 4030 sm.select(0); // select first row 4031 sm.select(0, table.getColumns().get(0)); // This line and the next should be no-ops 4032 sm.select(0, table.getColumns().get(1)); 4033 4034 assertFalse(sm.isSelected(0)); 4035 assertTrue(sm.isSelected(0, table.getColumns().get(0))); 4036 assertTrue(sm.isSelected(0, table.getColumns().get(1))); 4037 4038 assertEquals(1, sm.getSelectedIndices().size()); 4039 assertEquals(1, sm.getSelectedItems().size()); 4040 assertEquals(2, sm.getSelectedCells().size()); 4041 } 4042 4043 @Test public void test_rt38464_selectCellMultipleTimes() { 4044 TreeTableView<Person> table = test_rt_38464_createControl(); 4045 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 4046 sm.setCellSelectionEnabled(true); 4047 sm.setSelectionMode(SelectionMode.MULTIPLE); 4048 4049 // default selection when in cell selection mode 4050 assertEquals(0, sm.getSelectedCells().size()); 4051 assertEquals(0, sm.getSelectedItems().size()); 4052 assertEquals(0, sm.getSelectedIndices().size()); 4053 4054 // select the first cell 4055 sm.select(0, table.getColumns().get(0)); 4056 assertEquals(1, sm.getSelectedCells().size()); 4057 assertEquals(1, sm.getSelectedItems().size()); 4058 assertEquals(1, sm.getSelectedIndices().size()); 4059 4060 // select the first cell....again 4061 sm.select(0, table.getColumns().get(0)); 4062 assertEquals(1, sm.getSelectedCells().size()); 4063 assertEquals(1, sm.getSelectedItems().size()); 4064 assertEquals(1, sm.getSelectedIndices().size()); 4065 } 4066 4067 @Test public void test_rt38464_selectCellThenRow() { 4068 TreeTableView<Person> table = test_rt_38464_createControl(); 4069 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 4070 sm.setCellSelectionEnabled(true); 4071 sm.setSelectionMode(SelectionMode.MULTIPLE); 4072 4073 // default selection when in cell selection mode 4074 assertEquals(0, sm.getSelectedCells().size()); 4075 assertEquals(0, sm.getSelectedItems().size()); 4076 assertEquals(0, sm.getSelectedIndices().size()); 4077 4078 // select the first cell 4079 sm.select(0, table.getColumns().get(0)); 4080 assertEquals(1, sm.getSelectedCells().size()); 4081 assertEquals(1, sm.getSelectedItems().size()); 4082 assertEquals(1, sm.getSelectedIndices().size()); 4083 4084 // select the first row 4085 sm.select(0); 4086 4087 // we go to 2 here as all cells in the row become selected. What we do 4088 // not expect is to go to 3, as that would mean duplication 4089 assertEquals(2, sm.getSelectedCells().size()); 4090 assertEquals(1, sm.getSelectedItems().size()); 4091 assertEquals(1, sm.getSelectedIndices().size()); 4092 } 4093 4094 @Test public void test_rt38464_selectRowThenCell() { 4095 TreeTableView<Person> table = test_rt_38464_createControl(); 4096 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 4097 sm.setCellSelectionEnabled(true); 4098 sm.setSelectionMode(SelectionMode.MULTIPLE); 4099 4100 // default selection when in cell selection mode 4101 assertEquals(0, sm.getSelectedCells().size()); 4102 assertEquals(0, sm.getSelectedItems().size()); 4103 assertEquals(0, sm.getSelectedIndices().size()); 4104 4105 // select the first row 4106 sm.select(0); 4107 4108 // we go to 2 here as all cells in the row become selected. 4109 assertEquals(2, sm.getSelectedCells().size()); 4110 assertEquals(1, sm.getSelectedItems().size()); 4111 assertEquals(1, sm.getSelectedIndices().size()); 4112 4113 // select the first cell - no change is expected 4114 sm.select(0, table.getColumns().get(0)); 4115 assertEquals(2, sm.getSelectedCells().size()); 4116 assertEquals(1, sm.getSelectedItems().size()); 4117 assertEquals(1, sm.getSelectedIndices().size()); 4118 } 4119 4120 @Test public void test_rt38464_selectTests_cellSelection_singleSelection_selectsOneRow() { 4121 test_rt38464_selectTests(true, true, true); 4122 } 4123 4124 @Test public void test_rt38464_selectTests_cellSelection_singleSelection_selectsTwoRows() { 4125 test_rt38464_selectTests(true, true, false); 4126 } 4127 4128 @Test public void test_rt38464_selectTests_cellSelection_multipleSelection_selectsOneRow() { 4129 test_rt38464_selectTests(true, false, true); 4130 } 4131 4132 @Test public void test_rt38464_selectTests_cellSelection_multipleSelection_selectsTwoRows() { 4133 test_rt38464_selectTests(true, false, false); 4134 } 4135 4136 @Test public void test_rt38464_selectTests_rowSelection_singleSelection_selectsOneRow() { 4137 test_rt38464_selectTests(false, true, true); 4138 } 4139 4140 @Test public void test_rt38464_selectTests_rowSelection_singleSelection_selectsTwoRows() { 4141 test_rt38464_selectTests(false, true, false); 4142 } 4143 4144 @Test public void test_rt38464_selectTests_rowSelection_multipleSelection_selectsOneRow() { 4145 test_rt38464_selectTests(false, false, true); 4146 } 4147 4148 @Test public void test_rt38464_selectTests_rowSelection_multipleSelection_selectsTwoRows() { 4149 test_rt38464_selectTests(false, false, false); 4150 } 4151 4152 private void test_rt38464_selectTests(boolean cellSelection, boolean singleSelection, boolean selectsOneRow) { 4153 TreeTableView<Person> table = test_rt_38464_createControl(); 4154 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 4155 sm.setCellSelectionEnabled(cellSelection); 4156 sm.setSelectionMode(singleSelection ? SelectionMode.SINGLE : SelectionMode.MULTIPLE); 4157 4158 // default selection when in cell selection mode 4159 assertEquals(0, sm.getSelectedCells().size()); 4160 assertEquals(0, sm.getSelectedItems().size()); 4161 assertEquals(0, sm.getSelectedIndices().size()); 4162 4163 if (selectsOneRow) { 4164 sm.select(0); 4165 } else { 4166 // select the first two rows 4167 sm.selectIndices(0, 1); 4168 } 4169 4170 final int expectedCells = singleSelection ? 1 : 4171 selectsOneRow && cellSelection ? 2 : 4172 selectsOneRow && !cellSelection ? 1 : 4173 !selectsOneRow && cellSelection ? 4 : 4174 /* !selectsOneRow && !cellSelection */ 2; 4175 4176 final int expectedItems = singleSelection ? 1 : 4177 selectsOneRow ? 1 : 2; 4178 4179 assertEquals(expectedCells, sm.getSelectedCells().size()); 4180 assertEquals(expectedItems, sm.getSelectedItems().size()); 4181 assertEquals(expectedItems, sm.getSelectedIndices().size()); 4182 4183 // we expect the table column of all selected cells, in this instance, 4184 // to be null as we have not explicitly stated a column, nor have we clicked 4185 // on a column. The only alternative is to use the first column. 4186 for (TreeTablePosition<?,?> tp : sm.getSelectedCells()) { 4187 if (cellSelection) { 4188 assertNotNull(tp.getTableColumn()); 4189 } else { 4190 assertNull(tp.getTableColumn()); 4191 } 4192 } 4193 } 4194 4195 @Test public void test_rt_37853_replaceRoot() { 4196 test_rt_37853(true); 4197 } 4198 4199 @Test public void test_rt_37853_replaceRootChildren() { 4200 test_rt_37853(false); 4201 } 4202 4203 private int rt_37853_cancelCount; 4204 private int rt_37853_commitCount; 4205 public void test_rt_37853(boolean replaceRoot) { 4206 TreeTableColumn<String,String> first = new TreeTableColumn<>("first"); 4207 first.setEditable(true); 4208 first.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn()); 4209 treeTableView.getColumns().add(first); 4210 treeTableView.setEditable(true); 4211 treeTableView.setRoot(new TreeItem<>("Root")); 4212 treeTableView.getRoot().setExpanded(true); 4213 4214 for (int i = 0; i < 10; i++) { 4215 treeTableView.getRoot().getChildren().add(new TreeItem<>("" + i)); 4216 } 4217 4218 StageLoader sl = new StageLoader(treeTableView); 4219 4220 first.setOnEditCancel(editEvent -> rt_37853_cancelCount++); 4221 first.setOnEditCommit(editEvent -> rt_37853_commitCount++); 4222 4223 assertEquals(0, rt_37853_cancelCount); 4224 assertEquals(0, rt_37853_commitCount); 4225 4226 treeTableView.edit(1, first); 4227 assertNotNull(treeTableView.getEditingCell()); 4228 4229 if (replaceRoot) { 4230 treeTableView.setRoot(new TreeItem<>("New Root")); 4231 } else { 4232 treeTableView.getRoot().getChildren().clear(); 4233 for (int i = 0; i < 10; i++) { 4234 treeTableView.getRoot().getChildren().add(new TreeItem<>("new item " + i)); 4235 } 4236 } 4237 assertEquals(1, rt_37853_cancelCount); 4238 assertEquals(0, rt_37853_commitCount); 4239 4240 sl.dispose(); 4241 } 4242 4243 4244 /************************************************************************** 4245 * 4246 * Tests (and related code) for RT-38892 4247 * 4248 *************************************************************************/ 4249 4250 private final Supplier<TreeTableColumn<Person,String>> columnCallable = () -> { 4251 TreeTableColumn<Person,String> column = new TreeTableColumn<>("Last Name"); 4252 column.setCellValueFactory(new TreeItemPropertyValueFactory<Person,String>("lastName")); 4253 return column; 4254 }; 4255 4256 private TreeTableColumn<Person, String> test_rt_38892_firstNameCol; 4257 private TreeTableColumn<Person, String> test_rt_38892_lastNameCol; 4258 4259 private TreeTableView<Person> init_test_rt_38892() { 4260 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 4261 new TreeItem<>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 4262 new TreeItem<>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 4263 new TreeItem<>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 4264 new TreeItem<>(new Person("Emma", "Jones", "emma.jones@example.com")), 4265 new TreeItem<>(new Person("Michael", "Brown", "michael.brown@example.com"))); 4266 4267 TreeTableView<Person> table = new TreeTableView<>(); 4268 table.setShowRoot(false); 4269 table.getSelectionModel().setCellSelectionEnabled(true); 4270 table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 4271 4272 TreeItem<Person> root = new TreeItem<>(new Person("Root", null, null)); 4273 root.setExpanded(true); 4274 root.getChildren().setAll(persons); 4275 table.setRoot(root); 4276 4277 test_rt_38892_firstNameCol = new TreeTableColumn<>("First Name"); 4278 test_rt_38892_firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<>("firstName")); 4279 test_rt_38892_lastNameCol = columnCallable.get(); 4280 table.getColumns().addAll(test_rt_38892_firstNameCol, test_rt_38892_lastNameCol); 4281 4282 return table; 4283 } 4284 4285 @Test public void test_rt_38892_focusMovesToLeftWhenPossible() { 4286 TreeTableView<Person> table = init_test_rt_38892(); 4287 4288 TreeTableView.TreeTableViewFocusModel<Person> fm = table.getFocusModel(); 4289 fm.focus(0, test_rt_38892_lastNameCol); 4290 4291 // assert pre-conditions 4292 assertEquals(0, fm.getFocusedIndex()); 4293 assertEquals(0, fm.getFocusedCell().getRow()); 4294 assertEquals(test_rt_38892_lastNameCol, fm.getFocusedCell().getTableColumn()); 4295 assertEquals(1, fm.getFocusedCell().getColumn()); 4296 4297 // now remove column where focus is and replace it with a new column. 4298 // We expect focus to move to the left one cell. 4299 table.getColumns().remove(1); 4300 table.getColumns().add(columnCallable.get()); 4301 4302 assertEquals(0, fm.getFocusedIndex()); 4303 assertEquals(0, fm.getFocusedCell().getRow()); 4304 assertEquals(test_rt_38892_firstNameCol, fm.getFocusedCell().getTableColumn()); 4305 assertEquals(0, fm.getFocusedCell().getColumn()); 4306 } 4307 4308 @Test public void test_rt_38892_removeLeftMostColumn() { 4309 TreeTableView<Person> table = init_test_rt_38892(); 4310 4311 TreeTableView.TreeTableViewFocusModel<Person> fm = table.getFocusModel(); 4312 fm.focus(0, test_rt_38892_firstNameCol); 4313 4314 // assert pre-conditions 4315 assertEquals(0, fm.getFocusedIndex()); 4316 assertEquals(0, fm.getFocusedCell().getRow()); 4317 assertEquals(test_rt_38892_firstNameCol, fm.getFocusedCell().getTableColumn()); 4318 assertEquals(0, fm.getFocusedCell().getColumn()); 4319 4320 // now remove column where focus is and replace it with a new column. 4321 // In the current (non-specified) behavior, this results in focus being 4322 // shifted to a cell in the remaining column, even when we add a new column 4323 // as we index based on the column, not on its index. 4324 table.getColumns().remove(0); 4325 TreeTableColumn<Person,String> newColumn = columnCallable.get(); 4326 table.getColumns().add(0, newColumn); 4327 4328 assertEquals(0, fm.getFocusedIndex()); 4329 assertEquals(0, fm.getFocusedCell().getRow()); 4330 assertEquals(test_rt_38892_lastNameCol, fm.getFocusedCell().getTableColumn()); 4331 assertEquals(1, fm.getFocusedCell().getColumn()); 4332 } 4333 4334 @Test public void test_rt_38892_removeSelectionFromCellsInRemovedColumn() { 4335 TreeTableView<Person> table = init_test_rt_38892(); 4336 4337 TreeTableView.TreeTableViewSelectionModel sm = table.getSelectionModel(); 4338 sm.select(0, test_rt_38892_firstNameCol); 4339 sm.select(1, test_rt_38892_lastNameCol); // this should go 4340 sm.select(2, test_rt_38892_firstNameCol); 4341 sm.select(3, test_rt_38892_lastNameCol); // so should this 4342 sm.select(4, test_rt_38892_firstNameCol); 4343 4344 assertEquals(5, sm.getSelectedCells().size()); 4345 4346 table.getColumns().remove(1); 4347 4348 assertEquals(3, sm.getSelectedCells().size()); 4349 assertTrue(sm.isSelected(0, test_rt_38892_firstNameCol)); 4350 assertFalse(sm.isSelected(1, test_rt_38892_lastNameCol)); 4351 assertTrue(sm.isSelected(2, test_rt_38892_firstNameCol)); 4352 assertFalse(sm.isSelected(3, test_rt_38892_lastNameCol)); 4353 assertTrue(sm.isSelected(4, test_rt_38892_firstNameCol)); 4354 } 4355 4356 @Test public void test_rt_38787_remove_b() { 4357 // Remove 'b', selection moves to 'a' 4358 test_rt_38787("a", 0, 1); 4359 } 4360 4361 @Test public void test_rt_38787_remove_b_c() { 4362 // Remove 'b' and 'c', selection moves to 'a' 4363 test_rt_38787("a", 0, 1, 2); 4364 } 4365 4366 @Test public void test_rt_38787_remove_c_d() { 4367 // Remove 'c' and 'd', selection moves to 'b' 4368 test_rt_38787("b", 1, 2, 3); 4369 } 4370 4371 @Test public void test_rt_38787_remove_a() { 4372 // Remove 'a', selection moves to 'b', now in index 0 4373 test_rt_38787("b", 0, 0); 4374 } 4375 4376 private void test_rt_38787(String expectedItem, int expectedIndex, int... indicesToRemove) { 4377 TreeItem<String> a, b, c, d; 4378 TreeItem<String> root = new TreeItem<>("Root"); 4379 root.setExpanded(true); 4380 root.getChildren().addAll( 4381 a = new TreeItem<String>("a"), 4382 b = new TreeItem<String>("b"), 4383 c = new TreeItem<String>("c"), 4384 d = new TreeItem<String>("d") 4385 ); 4386 4387 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4388 stringTreeTableView.setShowRoot(false); 4389 4390 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4391 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4392 stringTreeTableView.getColumns().add(column); 4393 4394 MultipleSelectionModel<TreeItem<String>> sm = stringTreeTableView.getSelectionModel(); 4395 sm.select(b); 4396 4397 // test pre-conditions 4398 assertEquals(1, sm.getSelectedIndex()); 4399 assertEquals(1, (int)sm.getSelectedIndices().get(0)); 4400 assertEquals(b, sm.getSelectedItem()); 4401 assertEquals(b, sm.getSelectedItems().get(0)); 4402 assertFalse(sm.isSelected(0)); 4403 assertTrue(sm.isSelected(1)); 4404 assertFalse(sm.isSelected(2)); 4405 4406 // removing items 4407 List<TreeItem<String>> itemsToRemove = new ArrayList<>(indicesToRemove.length); 4408 for (int index : indicesToRemove) { 4409 itemsToRemove.add(root.getChildren().get(index)); 4410 } 4411 root.getChildren().removeAll(itemsToRemove); 4412 4413 // testing against expectations 4414 assertEquals(expectedIndex, sm.getSelectedIndex()); 4415 assertEquals(expectedIndex, (int)sm.getSelectedIndices().get(0)); 4416 assertEquals(expectedItem, sm.getSelectedItem().getValue()); 4417 assertEquals(expectedItem, sm.getSelectedItems().get(0).getValue()); 4418 } 4419 4420 private int rt_38341_indices_count = 0; 4421 private int rt_38341_items_count = 0; 4422 @Test public void test_rt_38341() { 4423 Callback<Integer, TreeItem<String>> callback = number -> { 4424 final TreeItem<String> root = new TreeItem<>("Root " + number); 4425 final TreeItem<String> child = new TreeItem<>("Child " + number); 4426 4427 root.getChildren().add(child); 4428 return root; 4429 }; 4430 4431 final TreeItem<String> root = new TreeItem<String>(); 4432 root.setExpanded(true); 4433 root.getChildren().addAll(callback.call(1), callback.call(2)); 4434 4435 final TreeTableView<String> treeTableView = new TreeTableView<>(root); 4436 treeTableView.setShowRoot(false); 4437 4438 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4439 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4440 treeTableView.getColumns().add(column); 4441 4442 MultipleSelectionModel<TreeItem<String>> sm = treeTableView.getSelectionModel(); 4443 sm.getSelectedIndices().addListener((ListChangeListener<Integer>) c -> rt_38341_indices_count++); 4444 sm.getSelectedItems().addListener((ListChangeListener<TreeItem<String>>) c -> rt_38341_items_count++); 4445 4446 assertEquals(0, rt_38341_indices_count); 4447 assertEquals(0, rt_38341_items_count); 4448 4449 // expand the first child of root, and select it (note: root isn't visible) 4450 root.getChildren().get(0).setExpanded(true); 4451 sm.select(1); 4452 assertEquals(1, sm.getSelectedIndex()); 4453 assertEquals(1, sm.getSelectedIndices().size()); 4454 assertEquals(1, (int)sm.getSelectedIndices().get(0)); 4455 assertEquals(1, sm.getSelectedItems().size()); 4456 assertEquals("Child 1", sm.getSelectedItem().getValue()); 4457 assertEquals("Child 1", sm.getSelectedItems().get(0).getValue()); 4458 4459 assertEquals(1, rt_38341_indices_count); 4460 assertEquals(1, rt_38341_items_count); 4461 4462 // now delete it 4463 root.getChildren().get(0).getChildren().remove(0); 4464 4465 // selection should move to the childs parent in index 0 4466 assertEquals(0, sm.getSelectedIndex()); 4467 assertEquals(1, sm.getSelectedIndices().size()); 4468 assertEquals(0, (int)sm.getSelectedIndices().get(0)); 4469 assertEquals(1, sm.getSelectedItems().size()); 4470 assertEquals("Root 1", sm.getSelectedItem().getValue()); 4471 assertEquals("Root 1", sm.getSelectedItems().get(0).getValue()); 4472 4473 // we also expect there to be an event in the selection model for 4474 // selected indices and selected items 4475 assertEquals(2, rt_38341_indices_count); 4476 assertEquals(2, rt_38341_items_count); 4477 } 4478 4479 private int rt_38943_index_count = 0; 4480 private int rt_38943_item_count = 0; 4481 @Test public void test_rt_38943() { 4482 TreeItem<String> root = new TreeItem<>("Root"); 4483 root.setExpanded(true); 4484 root.getChildren().addAll( 4485 new TreeItem<>("a"), 4486 new TreeItem<>("b"), 4487 new TreeItem<>("c"), 4488 new TreeItem<>("d") 4489 ); 4490 4491 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4492 stringTreeTableView.setShowRoot(false); 4493 4494 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4495 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4496 stringTreeTableView.getColumns().add(column); 4497 4498 MultipleSelectionModel<TreeItem<String>> sm = stringTreeTableView.getSelectionModel(); 4499 4500 sm.selectedIndexProperty().addListener((observable, oldValue, newValue) -> rt_38943_index_count++); 4501 sm.selectedItemProperty().addListener((observable, oldValue, newValue) -> rt_38943_item_count++); 4502 4503 assertEquals(-1, sm.getSelectedIndex()); 4504 assertNull(sm.getSelectedItem()); 4505 assertEquals(0, rt_38943_index_count); 4506 assertEquals(0, rt_38943_item_count); 4507 4508 sm.select(0); 4509 assertEquals(0, sm.getSelectedIndex()); 4510 assertEquals("a", sm.getSelectedItem().getValue()); 4511 assertEquals(1, rt_38943_index_count); 4512 assertEquals(1, rt_38943_item_count); 4513 4514 sm.clearSelection(0); 4515 assertEquals(-1, sm.getSelectedIndex()); 4516 assertNull(sm.getSelectedItem()); 4517 assertEquals(2, rt_38943_index_count); 4518 assertEquals(2, rt_38943_item_count); 4519 } 4520 4521 @Test public void test_rt_38884() { 4522 final TreeItem<String> root = new TreeItem<>("Root"); 4523 final TreeItem<String> foo = new TreeItem<>("foo"); 4524 4525 TreeTableView<String> treeView = new TreeTableView<>(root); 4526 treeView.setShowRoot(false); 4527 root.setExpanded(true); 4528 4529 treeView.getSelectionModel().getSelectedItems().addListener((ListChangeListener.Change<? extends TreeItem<String>> c) -> { 4530 while (c.next()) { 4531 if (c.wasRemoved()) { 4532 assertTrue(c.getRemovedSize() > 0); 4533 4534 List<? extends TreeItem<String>> removed = c.getRemoved(); 4535 TreeItem<String> removedItem = null; 4536 try { 4537 removedItem = removed.get(0); 4538 } catch (Exception e) { 4539 fail(); 4540 } 4541 4542 assertEquals(foo, removedItem); 4543 } 4544 } 4545 }); 4546 4547 root.getChildren().add(foo); 4548 treeView.getSelectionModel().select(0); 4549 root.getChildren().clear(); 4550 } 4551 4552 private int rt_37360_add_count = 0; 4553 private int rt_37360_remove_count = 0; 4554 @Test public void test_rt_37360() { 4555 TreeItem<String> root = new TreeItem<>("Root"); 4556 root.setExpanded(true); 4557 root.getChildren().addAll( 4558 new TreeItem<>("a"), 4559 new TreeItem<>("b") 4560 ); 4561 4562 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4563 stringTreeTableView.setShowRoot(false); 4564 4565 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4566 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4567 stringTreeTableView.getColumns().add(column); 4568 4569 MultipleSelectionModel<TreeItem<String>> sm = stringTreeTableView.getSelectionModel(); 4570 sm.setSelectionMode(SelectionMode.MULTIPLE); 4571 sm.getSelectedItems().addListener((ListChangeListener<TreeItem<String>>) c -> { 4572 while (c.next()) { 4573 if (c.wasAdded()) { 4574 rt_37360_add_count += c.getAddedSize(); 4575 } 4576 if (c.wasRemoved()) { 4577 rt_37360_remove_count += c.getRemovedSize(); 4578 } 4579 } 4580 }); 4581 4582 assertEquals(0, sm.getSelectedItems().size()); 4583 assertEquals(0, rt_37360_add_count); 4584 assertEquals(0, rt_37360_remove_count); 4585 4586 sm.select(0); 4587 assertEquals(1, sm.getSelectedItems().size()); 4588 assertEquals(1, rt_37360_add_count); 4589 assertEquals(0, rt_37360_remove_count); 4590 4591 sm.select(1); 4592 assertEquals(2, sm.getSelectedItems().size()); 4593 assertEquals(2, rt_37360_add_count); 4594 assertEquals(0, rt_37360_remove_count); 4595 4596 sm.clearAndSelect(1); 4597 assertEquals(1, sm.getSelectedItems().size()); 4598 assertEquals(2, rt_37360_add_count); 4599 assertEquals(1, rt_37360_remove_count); 4600 } 4601 4602 private int rt_37366_count = 0; 4603 @Test public void test_rt_37366() { 4604 final TreeItem<String> treeItem2 = new TreeItem<>("Item 2"); 4605 treeItem2.getChildren().addAll(new TreeItem<>("Item 21"), new TreeItem<>("Item 22")); 4606 4607 final TreeItem<String> root1 = new TreeItem<>("Root Node 1"); 4608 root1.getChildren().addAll(new TreeItem<>("Item 1"), treeItem2, new TreeItem<>("Item 3")); 4609 root1.setExpanded(true); 4610 4611 final TreeItem<String> root2 = new TreeItem<>("Root Node 2"); 4612 4613 final TreeItem<String> hiddenRoot = new TreeItem<>("Hidden Root Node"); 4614 hiddenRoot.getChildren().add(root1); 4615 hiddenRoot.getChildren().add(root2); 4616 4617 final TreeTableView<String> treeView = new TreeTableView<>(hiddenRoot); 4618 treeView.setShowRoot(false); 4619 4620 MultipleSelectionModel<TreeItem<String>> sm = treeView.getSelectionModel(); 4621 sm.setSelectionMode(SelectionMode.MULTIPLE); 4622 sm.getSelectedItems().addListener((ListChangeListener.Change<? extends TreeItem<String>> c) -> { 4623 rt_37366_count++; 4624 }); 4625 4626 assertEquals(0, rt_37366_count); 4627 4628 sm.select(1); 4629 assertEquals(1, rt_37366_count); 4630 assertFalse(sm.isSelected(0)); 4631 assertTrue(sm.isSelected(1)); 4632 assertFalse(sm.isSelected(2)); 4633 4634 sm.select(2); 4635 assertEquals(2, rt_37366_count); 4636 assertFalse(sm.isSelected(0)); 4637 assertTrue(sm.isSelected(1)); 4638 assertTrue(sm.isSelected(2)); 4639 4640 root1.setExpanded(false); 4641 assertEquals(3, rt_37366_count); 4642 assertTrue(sm.isSelected(0)); 4643 assertFalse(sm.isSelected(1)); 4644 assertFalse(sm.isSelected(2)); 4645 } 4646 4647 @Test public void test_rt_38491() { 4648 TreeItem<String> a; 4649 TreeItem<String> root = new TreeItem<>("Root"); 4650 root.setExpanded(true); 4651 root.getChildren().addAll( 4652 a = new TreeItem<>("a"), 4653 new TreeItem<>("b") 4654 ); 4655 4656 TreeTableView<String> stringTreeView = new TreeTableView<>(root); 4657 stringTreeView.setShowRoot(false); 4658 4659 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4660 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4661 stringTreeView.getColumns().add(column); 4662 4663 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeView.getSelectionModel(); 4664 sm.setSelectionMode(SelectionMode.MULTIPLE); 4665 4666 TreeTableViewFocusModel<String> fm = stringTreeView.getFocusModel(); 4667 4668 StageLoader sl = new StageLoader(stringTreeView); 4669 4670 // test pre-conditions 4671 assertTrue(sm.isEmpty()); 4672 assertEquals(a, fm.getFocusedItem()); 4673 assertEquals(0, fm.getFocusedIndex()); 4674 4675 // click on row 0 4676 // VirtualFlowTestUtils.clickOnRow(stringTreeView, 0); 4677 sm.select(0, column); 4678 assertTrue(sm.isSelected(0)); 4679 assertEquals(a, sm.getSelectedItem()); 4680 assertTrue(fm.isFocused(0)); 4681 assertEquals(a, fm.getFocusedItem()); 4682 assertEquals(0, fm.getFocusedIndex()); 4683 assertEquals(0, fm.getFocusedCell().getRow()); 4684 assertEquals(column, fm.getFocusedCell().getTableColumn()); 4685 4686 TreeTablePosition<String, ?> anchor = TreeTableCellBehavior.getAnchor(stringTreeView, null); 4687 assertNotNull(anchor); 4688 assertTrue(TreeTableCellBehavior.hasNonDefaultAnchor(stringTreeView)); 4689 assertEquals(0, anchor.getRow()); 4690 4691 // now add a new item at row 0. This has the effect of pushing down 4692 // the selected item into row 1. 4693 root.getChildren().add(0, new TreeItem("z")); 4694 4695 // The first bug was that selection and focus were not moving down to 4696 // be on row 1, so we test that now 4697 assertFalse(sm.isSelected(0)); 4698 assertFalse(fm.isFocused(0)); 4699 assertTrue(sm.isSelected(1)); 4700 assertEquals(a, sm.getSelectedItem()); 4701 assertTrue(fm.isFocused(1)); 4702 assertEquals(a, fm.getFocusedItem()); 4703 assertEquals(1, fm.getFocusedIndex()); 4704 assertEquals(1, fm.getFocusedCell().getRow()); 4705 assertEquals(column, fm.getFocusedCell().getTableColumn()); 4706 4707 // The second bug was that the anchor was not being pushed down as well 4708 // (when it should). 4709 anchor = TreeTableCellBehavior.getAnchor(stringTreeView, null); 4710 assertNotNull(anchor); 4711 assertTrue(TreeTableCellBehavior.hasNonDefaultAnchor(stringTreeView)); 4712 assertEquals(1, anchor.getRow()); 4713 assertEquals(column, anchor.getTableColumn()); 4714 4715 sl.dispose(); 4716 } 4717 4718 private final ObservableList<TreeItem<String>> rt_39256_list = FXCollections.observableArrayList(); 4719 @Test public void test_rt_39256() { 4720 TreeItem<String> root = new TreeItem<>("Root"); 4721 root.setExpanded(true); 4722 root.getChildren().addAll( 4723 new TreeItem<>("a"), 4724 new TreeItem<>("b"), 4725 new TreeItem<>("c"), 4726 new TreeItem<>("d") 4727 ); 4728 4729 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4730 stringTreeTableView.setShowRoot(false); 4731 4732 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4733 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4734 stringTreeTableView.getColumns().add(column); 4735 4736 MultipleSelectionModel<TreeItem<String>> sm = stringTreeTableView.getSelectionModel(); 4737 sm.setSelectionMode(SelectionMode.MULTIPLE); 4738 4739 // rt_39256_list.addListener((ListChangeListener<TreeItem<String>>) change -> { 4740 // while (change.next()) { 4741 // System.err.println("number of selected persons (in bound list): " + change.getList().size()); 4742 // } 4743 // }); 4744 4745 Bindings.bindContent(rt_39256_list, sm.getSelectedItems()); 4746 4747 assertEquals(0, sm.getSelectedItems().size()); 4748 assertEquals(0, rt_39256_list.size()); 4749 4750 sm.selectAll(); 4751 assertEquals(4, sm.getSelectedItems().size()); 4752 assertEquals(4, rt_39256_list.size()); 4753 4754 sm.selectAll(); 4755 assertEquals(4, sm.getSelectedItems().size()); 4756 assertEquals(4, rt_39256_list.size()); 4757 4758 sm.selectAll(); 4759 assertEquals(4, sm.getSelectedItems().size()); 4760 assertEquals(4, rt_39256_list.size()); 4761 } 4762 4763 private final ObservableList<TreeItem<String>> rt_39482_list = FXCollections.observableArrayList(); 4764 @Test public void test_rt_39482() { 4765 TreeItem<String> root = new TreeItem<>("Root"); 4766 root.setExpanded(true); 4767 root.getChildren().addAll( 4768 new TreeItem<>("a"), 4769 new TreeItem<>("b"), 4770 new TreeItem<>("c"), 4771 new TreeItem<>("d") 4772 ); 4773 4774 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4775 stringTreeTableView.setShowRoot(false); 4776 4777 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4778 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4779 stringTreeTableView.getColumns().add(column); 4780 4781 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 4782 sm.setSelectionMode(SelectionMode.MULTIPLE); 4783 4784 // rt_39256_list.addListener((ListChangeListener<TreeItem<String>>) change -> { 4785 // while (change.next()) { 4786 // System.err.println("number of selected persons (in bound list): " + change.getList().size()); 4787 // } 4788 // }); 4789 4790 Bindings.bindContent(rt_39482_list, sm.getSelectedItems()); 4791 4792 assertEquals(0, sm.getSelectedItems().size()); 4793 assertEquals(0, rt_39482_list.size()); 4794 4795 test_rt_39482_selectRow("a", sm, 0, column); 4796 test_rt_39482_selectRow("b", sm, 1, column); 4797 test_rt_39482_selectRow("c", sm, 2, column); 4798 test_rt_39482_selectRow("d", sm, 3, column); 4799 } 4800 4801 private void test_rt_39482_selectRow(String expectedString, 4802 TreeTableView.TreeTableViewSelectionModel<String> sm, 4803 int rowToSelect, 4804 TreeTableColumn<String,String> columnToSelect) { 4805 System.out.println("\nSelect row " + rowToSelect); 4806 sm.selectAll(); 4807 assertEquals(4, sm.getSelectedCells().size()); 4808 assertEquals(4, sm.getSelectedIndices().size()); 4809 assertEquals(4, sm.getSelectedItems().size()); 4810 assertEquals(4, rt_39482_list.size()); 4811 4812 sm.clearAndSelect(rowToSelect, columnToSelect); 4813 assertEquals(1, sm.getSelectedCells().size()); 4814 assertEquals(1, sm.getSelectedIndices().size()); 4815 assertEquals(1, sm.getSelectedItems().size()); 4816 assertEquals(expectedString, sm.getSelectedItem().getValue()); 4817 assertEquals(expectedString, rt_39482_list.get(0).getValue()); 4818 assertEquals(1, rt_39482_list.size()); 4819 } 4820 4821 @Test public void test_rt_39559_useSM_selectAll() { 4822 test_rt_39559(true); 4823 } 4824 4825 @Test public void test_rt_39559_useKeyboard_selectAll() { 4826 test_rt_39559(false); 4827 } 4828 4829 private void test_rt_39559(boolean useSMSelectAll) { 4830 TreeItem<String> a, b; 4831 TreeItem<String> root = new TreeItem<>("Root"); 4832 root.setExpanded(true); 4833 root.getChildren().addAll( 4834 a = new TreeItem<>("a"), 4835 b = new TreeItem<>("b"), 4836 new TreeItem<>("c"), 4837 new TreeItem<>("d") 4838 ); 4839 4840 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4841 stringTreeTableView.setShowRoot(false); 4842 4843 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4844 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4845 stringTreeTableView.getColumns().add(column); 4846 4847 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 4848 sm.setSelectionMode(SelectionMode.MULTIPLE); 4849 4850 StageLoader sl = new StageLoader(stringTreeTableView); 4851 KeyEventFirer keyboard = new KeyEventFirer(stringTreeTableView); 4852 4853 assertEquals(0, sm.getSelectedItems().size()); 4854 4855 sm.clearAndSelect(0); 4856 4857 if (useSMSelectAll) { 4858 sm.selectAll(); 4859 } else { 4860 keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey()); 4861 } 4862 4863 assertEquals(4, sm.getSelectedItems().size()); 4864 assertEquals(0, ((TreeTablePosition) TreeTableCellBehavior.getAnchor(stringTreeTableView, null)).getRow()); 4865 4866 keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); 4867 4868 assertEquals(0, ((TreeTablePosition) TreeTableCellBehavior.getAnchor(stringTreeTableView, null)).getRow()); 4869 assertEquals(2, sm.getSelectedItems().size()); 4870 assertEquals(a, sm.getSelectedItems().get(0)); 4871 assertEquals(b, sm.getSelectedItems().get(1)); 4872 4873 sl.dispose(); 4874 } 4875 4876 @Test public void test_rt_16068_firstElement_selectAndRemoveSameRow() { 4877 // select and then remove the 'a' item, selection and focus should both 4878 // stay at the first row, now 'b' 4879 test_rt_16068(0, 0, 0); 4880 } 4881 4882 @Test public void test_rt_16068_firstElement_selectRowAndRemoveLaterSibling() { 4883 // select row 'a', and remove row 'c', selection and focus should not change 4884 test_rt_16068(0, 2, 0); 4885 } 4886 4887 @Test public void test_rt_16068_middleElement_selectAndRemoveSameRow() { 4888 // select and then remove the 'b' item, selection and focus should both 4889 // move up one row to the 'a' item 4890 test_rt_16068(1, 1, 0); 4891 } 4892 4893 @Test public void test_rt_16068_middleElement_selectRowAndRemoveLaterSibling() { 4894 // select row 'b', and remove row 'c', selection and focus should not change 4895 test_rt_16068(1, 2, 1); 4896 } 4897 4898 @Test public void test_rt_16068_middleElement_selectRowAndRemoveEarlierSibling() { 4899 // select row 'b', and remove row 'a', selection and focus should move up 4900 // one row, remaining on 'b' 4901 test_rt_16068(1, 0, 0); 4902 } 4903 4904 @Test public void test_rt_16068_lastElement_selectAndRemoveSameRow() { 4905 // select and then remove the 'd' item, selection and focus should both 4906 // move up one row to the 'c' item 4907 test_rt_16068(3, 3, 2); 4908 } 4909 4910 @Test public void test_rt_16068_lastElement_selectRowAndRemoveEarlierSibling() { 4911 // select row 'd', and remove row 'a', selection and focus should move up 4912 // one row, remaining on 'd' 4913 test_rt_16068(3, 0, 2); 4914 } 4915 4916 private void test_rt_16068(int indexToSelect, int indexToRemove, int expectedIndex) { 4917 TreeItem<String> root = new TreeItem<>("Root"); 4918 root.setExpanded(true); 4919 root.getChildren().addAll( 4920 new TreeItem<>("a"), // 0 4921 new TreeItem<>("b"), // 1 4922 new TreeItem<>("c"), // 2 4923 new TreeItem<>("d") // 3 4924 ); 4925 4926 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4927 stringTreeTableView.setShowRoot(false); 4928 4929 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 4930 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4931 stringTreeTableView.getColumns().add(column); 4932 4933 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 4934 FocusModel<TreeItem<String>> fm = stringTreeTableView.getFocusModel(); 4935 4936 sm.select(indexToSelect); 4937 assertEquals(indexToSelect, sm.getSelectedIndex()); 4938 assertEquals(root.getChildren().get(indexToSelect).getValue(), sm.getSelectedItem().getValue()); 4939 assertEquals(indexToSelect, fm.getFocusedIndex()); 4940 assertEquals(root.getChildren().get(indexToSelect).getValue(), fm.getFocusedItem().getValue()); 4941 4942 root.getChildren().remove(indexToRemove); 4943 assertEquals(expectedIndex, sm.getSelectedIndex()); 4944 assertEquals(root.getChildren().get(expectedIndex).getValue(), sm.getSelectedItem().getValue()); 4945 assertEquals(debug(), expectedIndex, fm.getFocusedIndex()); 4946 assertEquals(root.getChildren().get(expectedIndex).getValue(), fm.getFocusedItem().getValue()); 4947 } 4948 4949 @Test public void test_rt_39675() { 4950 TreeItem<String> b; 4951 TreeItem<String> root = new TreeItem<>("Root"); 4952 root.setExpanded(true); 4953 root.getChildren().addAll( 4954 new TreeItem<>("a"), 4955 b = new TreeItem<>("b"), 4956 new TreeItem<>("c"), 4957 new TreeItem<>("d") 4958 ); 4959 4960 b.setExpanded(true); 4961 b.getChildren().addAll( 4962 new TreeItem<>("b1"), 4963 new TreeItem<>("b2"), 4964 new TreeItem<>("b3"), 4965 new TreeItem<>("b4") 4966 ); 4967 4968 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 4969 4970 TreeTableColumn<String,String> column0 = new TreeTableColumn<>("Column1"); 4971 column0.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4972 4973 TreeTableColumn<String,String> column1 = new TreeTableColumn<>("Column2"); 4974 column1.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4975 4976 TreeTableColumn<String,String> column2 = new TreeTableColumn<>("Column3"); 4977 column2.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 4978 4979 stringTreeTableView.getColumns().addAll(column0, column1, column2); 4980 4981 sm = stringTreeTableView.getSelectionModel(); 4982 sm.setSelectionMode(SelectionMode.SINGLE); 4983 sm.setCellSelectionEnabled(true); 4984 4985 StageLoader sl = new StageLoader(stringTreeTableView); 4986 4987 assertEquals(0, sm.getSelectedItems().size()); 4988 4989 sm.clearAndSelect(4, column0); // select 'b2' in row 4, column 0 4990 assertTrue(sm.isSelected(4, column0)); 4991 assertEquals(1, sm.getSelectedCells().size()); 4992 assertEquals("b2", ((TreeItem)sm.getSelectedItem()).getValue()); 4993 4994 // collapse the 'b' tree item, selection and focus should go to 4995 // the 'b' tree item in row 2, column 0 4996 b.setExpanded(false); 4997 assertTrue(sm.isSelected(2, column0)); 4998 assertEquals(1, sm.getSelectedCells().size()); 4999 assertEquals("b", ((TreeItem)sm.getSelectedItem()).getValue()); 5000 5001 sl.dispose(); 5002 } 5003 5004 5005 private ObservableList<String> test_rt_39661_setup() { 5006 ObservableList<String> rawItems = FXCollections.observableArrayList( 5007 "9-item", "8-item", "7-item", "6-item", 5008 "5-item", "4-item", "3-item", "2-item", "1-item"); 5009 root = createSubTree("root", rawItems); 5010 root.setExpanded(true); 5011 treeTableView = new TreeTableView(root); 5012 return rawItems; 5013 } 5014 5015 private TreeItem createSubTree(Object item, ObservableList<String> rawItems) { 5016 TreeItem child = new TreeItem(item); 5017 child.getChildren().setAll(rawItems.stream() 5018 .map(rawItem -> new TreeItem(rawItem)) 5019 .collect(Collectors.toList())); 5020 return child; 5021 } 5022 5023 @Test public void test_rt_39661_rowLessThanExpandedItemCount() { 5024 ObservableList<String> rawItems = test_rt_39661_setup(); 5025 TreeItem child = createSubTree("child", rawItems); 5026 TreeItem grandChild = (TreeItem) child.getChildren().get(rawItems.size() - 1); 5027 root.getChildren().add(child); 5028 assertTrue("row of item must be less than expandedItemCount, but was: " + treeTableView.getRow(grandChild), 5029 treeTableView.getRow(grandChild) < treeTableView.getExpandedItemCount()); 5030 } 5031 5032 @Test public void test_rt_39661_rowOfGrandChildParentCollapsedUpdatedOnInsertAbove() { 5033 ObservableList<String> rawItems = test_rt_39661_setup(); 5034 int grandIndex = 2; 5035 int childIndex = 3; 5036 5037 TreeItem child = createSubTree("addedChild2", rawItems); 5038 TreeItem grandChild = (TreeItem) child.getChildren().get(grandIndex); 5039 root.getChildren().add(childIndex, child); 5040 5041 int rowOfGrand = treeTableView.getRow(grandChild); 5042 root.getChildren().add(childIndex - 1, createSubTree("other", rawItems)); 5043 5044 assertEquals(-1, treeTableView.getRow(grandChild)); 5045 } 5046 5047 @Test public void test_rt_39661_rowOfGrandChildParentCollapsedUpdatedOnInsertAboveWithoutAccess() { 5048 ObservableList<String> rawItems = test_rt_39661_setup(); 5049 int grandIndex = 2; 5050 int childIndex = 3; 5051 5052 TreeItem child = createSubTree("addedChild2", rawItems); 5053 TreeItem grandChild = (TreeItem) child.getChildren().get(grandIndex); 5054 root.getChildren().add(childIndex, child); 5055 5056 int rowOfGrand = 7; //treeTableView.getRow(grandChild); 5057 root.getChildren().add(childIndex, createSubTree("other", rawItems)); 5058 5059 assertEquals(-1, treeTableView.getRow(grandChild)); 5060 } 5061 5062 @Test public void test_rt_39661_rowOfGrandChildParentExpandedUpdatedOnInsertAbove() { 5063 ObservableList<String> rawItems = test_rt_39661_setup(); 5064 int grandIndex = 2; 5065 int childIndex = 3; 5066 TreeItem child = createSubTree("addedChild2", rawItems); 5067 TreeItem grandChild = (TreeItem) child.getChildren().get(grandIndex); 5068 child.setExpanded(true); 5069 root.getChildren().add(childIndex, child); 5070 int rowOfGrand = treeTableView.getRow(grandChild); 5071 root.getChildren().add(childIndex -1, createSubTree("other", rawItems)); 5072 assertEquals(rowOfGrand + 1, treeTableView.getRow(grandChild)); 5073 } 5074 5075 /** 5076 * Testing getRow on grandChild: compare collapsed/expanded parent. 5077 */ 5078 @Test public void test_rt_39661_rowOfGrandChildDependsOnParentExpansion() { 5079 ObservableList<String> rawItems = test_rt_39661_setup(); 5080 int grandIndex = 2; 5081 int childIndex = 3; 5082 5083 TreeItem collapsedChild = createSubTree("addedChild", rawItems); 5084 TreeItem collapsedGrandChild = (TreeItem) collapsedChild.getChildren().get(grandIndex); 5085 root.getChildren().add(childIndex, collapsedChild); 5086 5087 int collapedGrandIndex = treeTableView.getRow(collapsedGrandChild); 5088 int collapsedRowCount = treeTableView.getExpandedItemCount(); 5089 5090 // start again 5091 test_rt_39661_setup(); 5092 assertEquals(collapsedRowCount - 1, treeTableView.getExpandedItemCount()); 5093 TreeItem expandedChild = createSubTree("addedChild2", rawItems); 5094 TreeItem expandedGrandChild = (TreeItem) expandedChild.getChildren().get(grandIndex); 5095 expandedChild.setExpanded(true); 5096 5097 root.getChildren().add(childIndex, expandedChild); 5098 assertNotSame("getRow must depend on expansionState " + collapedGrandIndex, 5099 collapedGrandIndex, treeTableView.getRow(expandedGrandChild)); 5100 } 5101 5102 @Test public void test_rt_39661_rowOfGrandChildInCollapsedChild() { 5103 ObservableList<String> rawItems = test_rt_39661_setup(); 5104 5105 // create a collapsed new child to insert into the root 5106 TreeItem newChild = createSubTree("added-child", rawItems); 5107 TreeItem grandChild = (TreeItem) newChild.getChildren().get(2); 5108 root.getChildren().add(6, newChild); 5109 5110 // query the row of a grand-child 5111 int row = treeTableView.getRow(grandChild); 5112 5113 // grandChild not visible, row coordinate in tree is not available 5114 assertEquals("grandChild not visible", -1, row); 5115 5116 // the other way round: if we get a row, expect the item at the row be the grandChild 5117 if (row > -1) { 5118 assertEquals(grandChild, treeTableView.getTreeItem(row)); 5119 } 5120 } 5121 5122 @Test public void test_rt_39661_rowOfRootChild() { 5123 ObservableList<String> rawItems = test_rt_39661_setup(); 5124 int index = 2; 5125 5126 TreeItem child = (TreeItem) root.getChildren().get(index); 5127 assertEquals(index + 1, treeTableView.getRow(child)); 5128 } 5129 5130 @Test public void test_rt_39661_expandedItemCount() { 5131 ObservableList<String> rawItems = test_rt_39661_setup(); 5132 int initialRowCount = treeTableView.getExpandedItemCount(); 5133 assertEquals(root.getChildren().size() + 1, initialRowCount); 5134 5135 TreeItem collapsedChild = createSubTree("collapsed-child", rawItems); 5136 root.getChildren().add(collapsedChild); 5137 assertEquals(initialRowCount + 1, treeTableView.getExpandedItemCount()); 5138 5139 TreeItem expandedChild = createSubTree("expanded-child", rawItems); 5140 expandedChild.setExpanded(true); 5141 root.getChildren().add(0, expandedChild); 5142 assertEquals(2 * initialRowCount + 1, treeTableView.getExpandedItemCount()); 5143 } 5144 5145 private int test_rt_39822_count = 0; 5146 @Test public void test_rt_39822() { 5147 // get the current exception handler before replacing with our own, 5148 // as ListListenerHelp intercepts the exception otherwise 5149 final Thread.UncaughtExceptionHandler exceptionHandler = Thread.currentThread().getUncaughtExceptionHandler(); 5150 Thread.currentThread().setUncaughtExceptionHandler((t, e) -> { 5151 e.printStackTrace(); 5152 5153 if (test_rt_39822_count == 0) { 5154 test_rt_39822_count++; 5155 if (! (e instanceof IllegalStateException)) { 5156 fail("Incorrect exception type - expecting IllegalStateException"); 5157 } 5158 } else { 5159 // don't care 5160 test_rt_39822_count++; 5161 } 5162 }); 5163 5164 TreeTableView<String> table = new TreeTableView<>(); 5165 TreeTableColumn<String, String> col1 = new TreeTableColumn<>("Foo"); 5166 table.getColumns().addAll(col1, col1); // add column twice 5167 5168 StageLoader sl = null; 5169 try { 5170 sl = new StageLoader(table); 5171 } finally { 5172 if (sl != null) { 5173 sl.dispose(); 5174 } 5175 5176 // reset the exception handler 5177 Thread.currentThread().setUncaughtExceptionHandler(exceptionHandler); 5178 } 5179 } 5180 5181 private int test_rt_39842_count = 0; 5182 @Test public void test_rt_39842_selectLeftDown() { 5183 test_rt_39842(true, false); 5184 } 5185 5186 @Test public void test_rt_39842_selectLeftUp() { 5187 test_rt_39842(true, true); 5188 } 5189 5190 @Test public void test_rt_39842_selectRightDown() { 5191 test_rt_39842(false, false); 5192 } 5193 5194 @Test public void test_rt_39842_selectRightUp() { 5195 test_rt_39842(false, true); 5196 } 5197 5198 private void test_rt_39842(boolean selectToLeft, boolean selectUpwards) { 5199 test_rt_39842_count = 0; 5200 5201 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 5202 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 5203 5204 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 5205 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 5206 5207 TreeItem root = new TreeItem("root"); 5208 root.getChildren().setAll( 5209 new TreeItem(new Person("Jacob", "Smith", "jacob.smith@example.com")), 5210 new TreeItem(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 5211 new TreeItem(new Person("Ethan", "Williams", "ethan.williams@example.com")), 5212 new TreeItem(new Person("Emma", "Jones", "emma.jones@example.com")), 5213 new TreeItem(new Person("Michael", "Brown", "michael.brown@example.com"))); 5214 root.setExpanded(true); 5215 5216 TreeTableView<Person> table = new TreeTableView<>(root); 5217 table.setShowRoot(false); 5218 table.getColumns().addAll(firstNameCol, lastNameCol); 5219 5220 sm = table.getSelectionModel(); 5221 sm.setCellSelectionEnabled(true); 5222 sm.setSelectionMode(SelectionMode.MULTIPLE); 5223 sm.getSelectedCells().addListener((ListChangeListener) c -> test_rt_39842_count++); 5224 5225 StageLoader sl = new StageLoader(table); 5226 5227 assertEquals(0, test_rt_39842_count); 5228 5229 if (selectToLeft) { 5230 if (selectUpwards) { 5231 sm.selectRange(3, lastNameCol, 0, firstNameCol); 5232 } else { 5233 sm.selectRange(0, lastNameCol, 3, firstNameCol); 5234 } 5235 } else { 5236 if (selectUpwards) { 5237 sm.selectRange(3, firstNameCol, 0, lastNameCol); 5238 } else { 5239 sm.selectRange(0, firstNameCol, 3, lastNameCol); 5240 } 5241 } 5242 5243 // test model state 5244 assertEquals(8, sm.getSelectedCells().size()); 5245 assertEquals(1, test_rt_39842_count); 5246 5247 // test visual state 5248 for (int row = 0; row <= 3; row++) { 5249 for (int column = 0; column <= 1; column++) { 5250 IndexedCell cell = VirtualFlowTestUtils.getCell(table, row, column); 5251 assertTrue(cell.isSelected()); 5252 } 5253 } 5254 5255 sl.dispose(); 5256 } 5257 5258 @Test public void test_rt_22599() { 5259 TreeItem<RT22599_DataType> root = new TreeItem<>(); 5260 root.getChildren().setAll( 5261 new TreeItem<>(new RT22599_DataType(1, "row1")), 5262 new TreeItem<>(new RT22599_DataType(2, "row2")), 5263 new TreeItem<>(new RT22599_DataType(3, "row3"))); 5264 root.setExpanded(true); 5265 5266 TreeTableColumn<RT22599_DataType, String> col = new TreeTableColumn<>("Header"); 5267 col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue().text)); 5268 5269 TreeTableView<RT22599_DataType> table = new TreeTableView<>(root); 5270 table.setShowRoot(false); 5271 table.getColumns().addAll(col); 5272 5273 StageLoader sl = new StageLoader(table); 5274 5275 // testing initial state 5276 assertNotNull(table.getSkin()); 5277 assertEquals("row1", VirtualFlowTestUtils.getCell(table, 0, 0).getText()); 5278 assertEquals("row2", VirtualFlowTestUtils.getCell(table, 1, 0).getText()); 5279 assertEquals("row3", VirtualFlowTestUtils.getCell(table, 2, 0).getText()); 5280 5281 // change row 0 (where "row1" currently resides), keeping same id. 5282 // Because 'set' is called, the control should update to the new content 5283 // without any user interaction 5284 TreeItem<RT22599_DataType> data; 5285 root.getChildren().set(0, data = new TreeItem<>(new RT22599_DataType(0, "row1a"))); 5286 Toolkit.getToolkit().firePulse(); 5287 assertEquals("row1a", VirtualFlowTestUtils.getCell(table, 0, 0).getText()); 5288 5289 // change the row 0 (where we currently have "row1a") value directly. 5290 // Because there is no associated property, this won't be observed, so 5291 // the control should still show "row1a" rather than "row1b" 5292 data.getValue().text = "row1b"; 5293 Toolkit.getToolkit().firePulse(); 5294 assertEquals("row1a", VirtualFlowTestUtils.getCell(table, 0, 0).getText()); 5295 5296 // call refresh() to force a refresh of all visible cells 5297 table.refresh(); 5298 Toolkit.getToolkit().firePulse(); 5299 assertEquals("row1b", VirtualFlowTestUtils.getCell(table, 0, 0).getText()); 5300 5301 sl.dispose(); 5302 } 5303 5304 private static class RT22599_DataType { 5305 public int id = 0; 5306 public String text = ""; 5307 5308 public RT22599_DataType(int id, String text) { 5309 this.id = id; 5310 this.text = text; 5311 } 5312 5313 @Override public boolean equals(Object obj) { 5314 if (obj == null) return false; 5315 return id == ((RT22599_DataType)obj).id; 5316 } 5317 } 5318 5319 private int rt_39966_count = 0; 5320 @Test public void test_rt_39966() { 5321 TreeItem<String> root = new TreeItem<>("Root"); 5322 TreeTableView<String> table = new TreeTableView<>(root); 5323 table.setShowRoot(true); 5324 5325 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5326 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5327 table.getColumns().add(column); 5328 5329 StageLoader sl = new StageLoader(table); 5330 5331 // initially there is no selection 5332 assertTrue(table.getSelectionModel().isEmpty()); 5333 5334 table.getSelectionModel().selectedItemProperty().addListener((value, s1, s2) -> { 5335 if (rt_39966_count == 0) { 5336 rt_39966_count++; 5337 assertFalse(table.getSelectionModel().isEmpty()); 5338 } else { 5339 assertTrue(table.getSelectionModel().isEmpty()); 5340 } 5341 }); 5342 5343 // our assertion two lines down always succeeds. What fails is our 5344 // assertion above within the listener. 5345 table.getSelectionModel().select(0); 5346 assertFalse(table.getSelectionModel().isEmpty()); 5347 5348 table.setRoot(null); 5349 assertTrue(table.getSelectionModel().isEmpty()); 5350 5351 sl.dispose(); 5352 } 5353 5354 /** 5355 * Bullet 1: selected index must be updated 5356 * Corner case: last selected. Fails for core 5357 */ 5358 @Test public void test_rt_40012_selectedAtLastOnDisjointRemoveItemsAbove() { 5359 TreeItem<String> root = new TreeItem<>("Root"); 5360 root.setExpanded(true); 5361 root.getChildren().addAll( 5362 new TreeItem<>("0"), 5363 new TreeItem<>("1"), 5364 new TreeItem<>("2"), 5365 new TreeItem<>("3"), 5366 new TreeItem<>("4"), 5367 new TreeItem<>("5") 5368 ); 5369 5370 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5371 stringTreeTableView.setShowRoot(false); 5372 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 5373 5374 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5375 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5376 stringTreeTableView.getColumns().add(column); 5377 5378 int last = root.getChildren().size() - 1; 5379 5380 // selecting item "5" 5381 sm.select(last); 5382 5383 // disjoint remove of 2 elements above the last selected 5384 // Removing "1" and "3" 5385 root.getChildren().removeAll(root.getChildren().get(1), root.getChildren().get(3)); 5386 5387 // selection should move up two places such that it remains on item "5", 5388 // but in index (last - 2). 5389 int expected = last - 2; 5390 assertEquals("5", sm.getSelectedItem().getValue()); 5391 assertEquals("selected index after disjoint removes above", expected, sm.getSelectedIndex()); 5392 } 5393 5394 /** 5395 * Variant of 1: if selectedIndex is not updated, 5396 * the old index is no longer valid 5397 * for accessing the items. 5398 */ 5399 @Test public void test_rt_40012_accessSelectedAtLastOnDisjointRemoveItemsAbove() { 5400 TreeItem<String> root = new TreeItem<>("Root"); 5401 root.setExpanded(true); 5402 root.getChildren().addAll( 5403 new TreeItem<>("0"), 5404 new TreeItem<>("1"), 5405 new TreeItem<>("2"), 5406 new TreeItem<>("3"), 5407 new TreeItem<>("4"), 5408 new TreeItem<>("5") 5409 ); 5410 5411 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5412 stringTreeTableView.setShowRoot(false); 5413 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 5414 5415 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5416 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5417 stringTreeTableView.getColumns().add(column); 5418 5419 int last = root.getChildren().size() - 1; 5420 5421 // selecting item "5" 5422 sm.select(last); 5423 5424 // disjoint remove of 2 elements above the last selected 5425 root.getChildren().removeAll(root.getChildren().get(1), root.getChildren().get(3)); 5426 int selected = sm.getSelectedIndex(); 5427 if (selected > -1) { 5428 root.getChildren().get(selected); 5429 } 5430 } 5431 5432 /** 5433 * Bullet 2: selectedIndex notification count 5434 * 5435 * Note that we don't use the corner case of having the last index selected 5436 * (which fails already on updating the index) 5437 */ 5438 private int rt_40012_count = 0; 5439 @Test public void test_rt_40012_selectedIndexNotificationOnDisjointRemovesAbove() { 5440 TreeItem<String> root = new TreeItem<>("Root"); 5441 root.setExpanded(true); 5442 root.getChildren().addAll( 5443 new TreeItem<>("0"), 5444 new TreeItem<>("1"), 5445 new TreeItem<>("2"), 5446 new TreeItem<>("3"), 5447 new TreeItem<>("4"), 5448 new TreeItem<>("5") 5449 ); 5450 5451 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5452 stringTreeTableView.setShowRoot(false); 5453 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 5454 5455 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5456 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5457 stringTreeTableView.getColumns().add(column); 5458 5459 int last = root.getChildren().size() - 2; 5460 sm.select(last); 5461 assertEquals(last, sm.getSelectedIndex()); 5462 5463 rt_40012_count = 0; 5464 sm.selectedIndexProperty().addListener(o -> rt_40012_count++); 5465 5466 // disjoint remove of 2 elements above the last selected 5467 root.getChildren().removeAll(root.getChildren().get(1), root.getChildren().get(3)); 5468 assertEquals("sanity: selectedIndex must be shifted by -2", last - 2, sm.getSelectedIndex()); 5469 assertEquals("must fire single event on removes above", 1, rt_40012_count); 5470 } 5471 5472 /** 5473 * Bullet 3: unchanged selectedItem must not fire change 5474 */ 5475 @Test 5476 public void test_rt_40012_selectedItemNotificationOnDisjointRemovesAbove() { 5477 TreeItem<String> root = new TreeItem<>("Root"); 5478 root.setExpanded(true); 5479 root.getChildren().addAll( 5480 new TreeItem<>("0"), 5481 new TreeItem<>("1"), 5482 new TreeItem<>("2"), 5483 new TreeItem<>("3"), 5484 new TreeItem<>("4"), 5485 new TreeItem<>("5") 5486 ); 5487 5488 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5489 stringTreeTableView.setShowRoot(false); 5490 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 5491 5492 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5493 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5494 stringTreeTableView.getColumns().add(column); 5495 5496 int last = root.getChildren().size() - 2; 5497 Object lastItem = root.getChildren().get(last); 5498 sm.select(last); 5499 assertEquals(lastItem, sm.getSelectedItem()); 5500 5501 rt_40012_count = 0; 5502 sm.selectedItemProperty().addListener(o -> rt_40012_count++); 5503 5504 // disjoint remove of 2 elements above the last selected 5505 root.getChildren().removeAll(root.getChildren().get(1), root.getChildren().get(3)); 5506 assertEquals("sanity: selectedItem unchanged", lastItem, sm.getSelectedItem()); 5507 assertEquals("must not fire on unchanged selected item", 0, rt_40012_count); 5508 } 5509 5510 private int rt_40010_count = 0; 5511 @Test public void test_rt_40010() { 5512 TreeItem<String> root = new TreeItem<>("Root"); 5513 TreeItem<String> child = new TreeItem<>("child"); 5514 root.setExpanded(true); 5515 root.getChildren().addAll(child); 5516 5517 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5518 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 5519 5520 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5521 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5522 stringTreeTableView.getColumns().add(column); 5523 5524 sm.getSelectedIndices().addListener((ListChangeListener<? super Integer>) l -> rt_40010_count++); 5525 sm.getSelectedItems().addListener((ListChangeListener<? super TreeItem<String>>) l -> rt_40010_count++); 5526 5527 assertEquals(0, rt_40010_count); 5528 5529 sm.select(1); 5530 assertEquals(1, sm.getSelectedIndex()); 5531 assertEquals(child, sm.getSelectedItem()); 5532 assertEquals(2, rt_40010_count); 5533 5534 root.getChildren().remove(child); 5535 assertEquals(0, sm.getSelectedIndex()); 5536 assertEquals(root, sm.getSelectedItem()); 5537 assertEquals(4, rt_40010_count); 5538 } 5539 5540 /** 5541 * ClearAndSelect fires invalid change event if selectedIndex is unchanged. 5542 */ 5543 private int rt_40212_count = 0; 5544 @Test public void test_rt_40212() { 5545 TreeItem<String> root = new TreeItem<>("Root"); 5546 root.setExpanded(true); 5547 root.getChildren().addAll( 5548 new TreeItem<>("0"), 5549 new TreeItem<>("1"), 5550 new TreeItem<>("2"), 5551 new TreeItem<>("3"), 5552 new TreeItem<>("4"), 5553 new TreeItem<>("5") 5554 ); 5555 5556 TreeTableView<String> stringTreeTableView = new TreeTableView<>(root); 5557 stringTreeTableView.setShowRoot(false); 5558 5559 TreeTableView.TreeTableViewSelectionModel<String> sm = stringTreeTableView.getSelectionModel(); 5560 sm.setSelectionMode(SelectionMode.MULTIPLE); 5561 5562 TreeTableColumn<String,String> column = new TreeTableColumn<>("Column"); 5563 column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5564 stringTreeTableView.getColumns().add(column); 5565 5566 sm.selectRange(3, 5); 5567 int selected = sm.getSelectedIndex(); 5568 5569 sm.getSelectedIndices().addListener((ListChangeListener<Integer>) change -> { 5570 assertEquals("sanity: selectedIndex unchanged", selected, sm.getSelectedIndex()); 5571 while(change.next()) { 5572 assertEquals("single event on clearAndSelect already selected", 1, ++rt_40212_count); 5573 5574 boolean type = change.wasAdded() || change.wasRemoved() || change.wasPermutated() || change.wasUpdated(); 5575 assertTrue("at least one of the change types must be true", type); 5576 } 5577 }); 5578 5579 sm.clearAndSelect(selected); 5580 } 5581 5582 @Test public void test_rt_40280() { 5583 final TreeTableView<String> view = new TreeTableView<>(); 5584 StageLoader sl = new StageLoader(view); 5585 view.getSelectionModel().getFocusedIndex(); 5586 view.getFocusModel().getFocusedIndex(); 5587 sl.dispose(); 5588 } 5589 5590 @Test public void test_rt_40278_showRoot() { 5591 TreeItem<String> root = new TreeItem<>("Root"); 5592 root.setExpanded(true); 5593 root.getChildren().addAll(new TreeItem<>("0"),new TreeItem<>("1")); 5594 5595 TreeTableView<String> view = new TreeTableView<>(root); 5596 view.setShowRoot(false); 5597 MultipleSelectionModel<TreeItem<String>> sm = view.getSelectionModel(); 5598 5599 assertFalse("sanity: test setup such that root is not showing", view.isShowRoot()); 5600 sm.select(0); 5601 assertEquals(0, sm.getSelectedIndex()); 5602 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 5603 view.setShowRoot(true); 5604 assertEquals(1, sm.getSelectedIndex()); 5605 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 5606 } 5607 5608 @Test public void test_rt_40278_hideRoot_selectionOnChild() { 5609 TreeItem<String> root = new TreeItem<>("Root"); 5610 root.setExpanded(true); 5611 root.getChildren().addAll(new TreeItem<>("0"),new TreeItem<>("1")); 5612 5613 TreeTableView<String> view = new TreeTableView<>(root); 5614 view.setShowRoot(true); 5615 MultipleSelectionModel<TreeItem<String>> sm = view.getSelectionModel(); 5616 5617 assertTrue("sanity: test setup such that root is showing", view.isShowRoot()); 5618 sm.select(1); 5619 assertEquals(1, sm.getSelectedIndex()); 5620 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 5621 view.setShowRoot(false); 5622 assertEquals(0, sm.getSelectedIndex()); 5623 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 5624 } 5625 5626 @Test public void test_rt_40278_hideRoot_selectionOnRoot() { 5627 TreeItem<String> root = new TreeItem<>("Root"); 5628 root.setExpanded(true); 5629 root.getChildren().addAll(new TreeItem<>("0"),new TreeItem<>("1")); 5630 5631 TreeTableView<String> view = new TreeTableView<>(root); 5632 view.setShowRoot(true); 5633 MultipleSelectionModel<TreeItem<String>> sm = view.getSelectionModel(); 5634 5635 assertTrue("sanity: test setup such that root is showing", view.isShowRoot()); 5636 sm.select(0); 5637 assertEquals(0, sm.getSelectedIndex()); 5638 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 5639 view.setShowRoot(false); 5640 assertEquals(0, sm.getSelectedIndex()); 5641 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 5642 } 5643 5644 /** 5645 * Test list change of selectedIndices on setIndices. Fails for core .. 5646 */ 5647 @Test public void test_rt_40263() { 5648 TreeItem<Integer> root = new TreeItem<>(-1); 5649 root.setExpanded(true); 5650 5651 for (int i = 0; i < 10; i++) { 5652 root.getChildren().add(new TreeItem<Integer>(i)); 5653 } 5654 5655 final TreeTableView<Integer> view = new TreeTableView<>(root); 5656 TreeTableView.TreeTableViewSelectionModel<Integer> sm = view.getSelectionModel(); 5657 sm.setSelectionMode(SelectionMode.MULTIPLE); 5658 5659 int[] indices = new int[]{2, 5, 7}; 5660 ListChangeListener<Integer> l = c -> { 5661 // firstly, we expect only one change 5662 int subChanges = 0; 5663 while(c.next()) { 5664 subChanges++; 5665 } 5666 assertEquals(1, subChanges); 5667 5668 // secondly, we expect the added size to be three, as that is the 5669 // number of items selected 5670 c.reset(); 5671 c.next(); 5672 System.out.println("Added items: " + c.getAddedSubList()); 5673 assertEquals(indices.length, c.getAddedSize()); 5674 assertArrayEquals(indices, c.getAddedSubList().stream().mapToInt(i -> i).toArray()); 5675 }; 5676 sm.getSelectedIndices().addListener(l); 5677 sm.selectIndices(indices[0], indices); 5678 } 5679 5680 @Test public void test_rt_40319_toRight_toBottom() { test_rt_40319(true, true, false); } 5681 @Test public void test_rt_40319_toRight_toTop() { test_rt_40319(true, false, false); } 5682 @Test public void test_rt_40319_toLeft_toBottom() { test_rt_40319(false, true, false); } 5683 @Test public void test_rt_40319_toLeft_toTop() { test_rt_40319(false, false, false); } 5684 @Test public void test_rt_40319_toRight_toBottom_useMouse() { test_rt_40319(true, true, true); } 5685 @Test public void test_rt_40319_toRight_toTop_useMouse() { test_rt_40319(true, false, true); } 5686 @Test public void test_rt_40319_toLeft_toBottom_useMouse() { test_rt_40319(false, true, true); } 5687 @Test public void test_rt_40319_toLeft_toTop_useMouse() { test_rt_40319(false, false, true); } 5688 5689 private void test_rt_40319(boolean toRight, boolean toBottom, boolean useMouse) { 5690 TreeItem<String> root = new TreeItem<>("Root"); 5691 root.setExpanded(true); 5692 root.getChildren().addAll( 5693 new TreeItem<>("0"), 5694 new TreeItem<>("1"), 5695 new TreeItem<>("2"), 5696 new TreeItem<>("3"), 5697 new TreeItem<>("4"), 5698 new TreeItem<>("5") 5699 ); 5700 5701 TreeTableView<String> t = new TreeTableView<>(root); 5702 t.setShowRoot(false); 5703 5704 sm = t.getSelectionModel(); 5705 sm.setSelectionMode(SelectionMode.MULTIPLE); 5706 5707 TreeTableColumn<String,String> c1 = new TreeTableColumn<>("Column"); 5708 c1.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5709 TreeTableColumn<String,String> c2 = new TreeTableColumn<>("Column"); 5710 c2.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue().getValue())); 5711 t.getColumns().addAll(c1, c2); 5712 5713 final int startIndex = toRight ? 0 : 2; 5714 final int endIndex = toRight ? 2 : 0; 5715 final TreeTableColumn<String,String> startColumn = toBottom ? c1 : c2; 5716 final TreeTableColumn<String,String> endColumn = toBottom ? c2 : c1; 5717 5718 sm.select(startIndex, startColumn); 5719 5720 if (useMouse) { 5721 Cell endCell = VirtualFlowTestUtils.getCell(t, endIndex, toRight ? 1 : 0); 5722 MouseEventFirer mouse = new MouseEventFirer(endCell); 5723 mouse.fireMousePressAndRelease(KeyModifier.SHIFT); 5724 } else { 5725 t.getSelectionModel().selectRange(startIndex, startColumn, endIndex, endColumn); 5726 } 5727 5728 assertEquals(3, sm.getSelectedItems().size()); 5729 assertEquals(3, sm.getSelectedIndices().size()); 5730 assertEquals(3, sm.getSelectedCells().size()); 5731 } 5732 }