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