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