1 /* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javafx.scene.control; 27 28 import com.sun.javafx.PlatformUtil; 29 import com.sun.javafx.util.Utils; 30 import com.sun.javafx.scene.control.behavior.TreeTableViewAnchorRetriever; 31 import com.sun.javafx.scene.control.infrastructure.*; 32 import com.sun.javafx.scene.control.skin.TreeTableViewSkin; 33 import com.sun.javafx.scene.control.test.Person; 34 35 import static org.junit.Assert.*; 36 37 import java.util.List; 38 39 import com.sun.javafx.tk.Toolkit; 40 import javafx.beans.value.ChangeListener; 41 import javafx.beans.value.ObservableValue; 42 import javafx.collections.FXCollections; 43 import javafx.collections.ListChangeListener; 44 import javafx.collections.ObservableList; 45 import javafx.scene.Group; 46 import javafx.scene.Node; 47 import javafx.scene.Scene; 48 import javafx.scene.control.cell.PropertyValueFactory; 49 import javafx.scene.control.cell.TreeItemPropertyValueFactory; 50 import javafx.scene.input.KeyCode; 51 52 import javafx.scene.layout.StackPane; 53 import javafx.scene.layout.VBox; 54 import javafx.stage.Stage; 55 import org.junit.After; 56 57 import org.junit.Before; 58 import org.junit.Ignore; 59 import org.junit.Test; 60 61 //@Ignore("Disabling tests as they fail with OOM in continuous builds") 62 public class TreeTableViewMouseInputTest { 63 private TreeTableView<String> tableView; 64 private TreeTableView.TreeTableViewSelectionModel<?> sm; 65 private TreeTableView.TreeTableViewFocusModel<?> fm; 66 67 private final TreeTableColumn<String, String> col0 = new TreeTableColumn<String, String>("col0"); 68 private final TreeTableColumn<String, String> col1 = new TreeTableColumn<String, String>("col1"); 69 private final TreeTableColumn<String, String> col2 = new TreeTableColumn<String, String>("col2"); 70 private final TreeTableColumn<String, String> col3 = new TreeTableColumn<String, String>("col3"); 71 private final TreeTableColumn<String, String> col4 = new TreeTableColumn<String, String>("col4"); 72 73 private TreeItem<String> root; // 0 74 private TreeItem<String> child1; // 1 75 private TreeItem<String> child2; // 2 76 private TreeItem<String> child3; // 3 77 private TreeItem<String> subchild1; // 4 78 private TreeItem<String> subchild2; // 5 79 private TreeItem<String> subchild3; // 6 80 private TreeItem<String> child4; // 7 81 private TreeItem<String> child5; // 8 82 private TreeItem<String> child6; // 9 83 private TreeItem<String> child7; // 10 84 private TreeItem<String> child8; // 11 85 private TreeItem<String> child9; // 12 86 private TreeItem<String> child10; // 13 87 88 @Before public void setup() { 89 root = new TreeItem<String>("Root"); // 0 90 child1 = new TreeItem<String>("Child 1"); // 1 91 child2 = new TreeItem<String>("Child 2"); // 2 92 child3 = new TreeItem<String>("Child 3"); // 3 93 subchild1 = new TreeItem<String>("Subchild 1"); // 4 94 subchild2 = new TreeItem<String>("Subchild 2"); // 5 95 subchild3 = new TreeItem<String>("Subchild 3"); // 6 96 child4 = new TreeItem<String>("Child 4"); // 7 97 child5 = new TreeItem<String>("Child 5"); // 8 98 child6 = new TreeItem<String>("Child 6"); // 9 99 child7 = new TreeItem<String>("Child 7"); // 10 100 child8 = new TreeItem<String>("Child 8"); // 11 101 child9 = new TreeItem<String>("Child 9"); // 12 102 child10 = new TreeItem<String>("Child 10"); // 13 103 104 // reset tree structure 105 root.getChildren().clear(); 106 root.setExpanded(true); 107 root.getChildren().setAll(child1, child2, child3, child4, child5, child6, child7, child8, child9, child10 ); 108 child1.getChildren().clear(); 109 child1.setExpanded(false); 110 child2.getChildren().clear(); 111 child2.setExpanded(false); 112 child3.getChildren().clear(); 113 child3.setExpanded(true); 114 child3.getChildren().setAll(subchild1, subchild2, subchild3); 115 child4.getChildren().clear(); 116 child4.setExpanded(false); 117 child5.getChildren().clear(); 118 child5.setExpanded(false); 119 child6.getChildren().clear(); 120 child6.setExpanded(false); 121 child7.getChildren().clear(); 122 child7.setExpanded(false); 123 child8.getChildren().clear(); 124 child8.setExpanded(false); 125 child9.getChildren().clear(); 126 child9.setExpanded(false); 127 child10.getChildren().clear(); 128 child10.setExpanded(false); 129 130 tableView = new TreeTableView<String>(); 131 sm = tableView.getSelectionModel(); 132 fm = tableView.getFocusModel(); 133 134 sm.setSelectionMode(SelectionMode.MULTIPLE); 135 sm.setCellSelectionEnabled(false); 136 137 tableView.setRoot(root); 138 tableView.getColumns().setAll(col0, col1, col2, col3, col4); 139 } 140 141 @After public void tearDown() { 142 if (tableView.getSkin() != null) { 143 tableView.getSkin().dispose(); 144 } 145 sm = null; 146 } 147 148 /*************************************************************************** 149 * Util methods 150 **************************************************************************/ 151 152 private String debug() { 153 StringBuilder sb = new StringBuilder("Selected Cells: ["); 154 155 ObservableList<? extends TreeTablePosition<?, ?>> cells = sm.getSelectedCells(); 156 for (TreeTablePosition<?,?> tp : cells) { 157 sb.append("("); 158 sb.append(tp.getRow()); 159 sb.append(","); 160 sb.append(tp.getColumn()); 161 sb.append("), "); 162 } 163 164 sb.append("] \nFocus: (" + fm.getFocusedCell().getRow() + ", " + fm.getFocusedCell().getColumn() + ")"); 165 166 TreeTablePosition anchor = getAnchor(); 167 sb.append(" \nAnchor: (" + (anchor == null ? "null" : anchor.getRow()) + 168 ", " + (anchor == null ? "null" : anchor.getColumn()) + ")"); 169 return sb.toString(); 170 } 171 172 // Returns true if ALL indices are selected 173 private boolean isSelected(int... indices) { 174 for (int index : indices) { 175 if (! sm.isSelected(index)) return false; 176 } 177 return true; 178 } 179 180 // Returns true if ALL indices are NOT selected 181 private boolean isNotSelected(int... indices) { 182 for (int index : indices) { 183 if (sm.isSelected(index)) return false; 184 } 185 return true; 186 } 187 188 private TreeTablePosition getAnchor() { 189 return TreeTableViewAnchorRetriever.getAnchor(tableView); 190 } 191 192 private boolean isAnchor(int row) { 193 TreeTablePosition tp = new TreeTablePosition(tableView, row, null); 194 return getAnchor() != null && getAnchor().equals(tp); 195 } 196 197 private boolean isAnchor(int row, int col) { 198 TreeTablePosition tp = new TreeTablePosition(tableView, row, tableView.getColumns().get(col)); 199 return getAnchor() != null && getAnchor().equals(tp); 200 } 201 202 private int getItemCount() { 203 return root.getChildren().size() + child3.getChildren().size(); 204 } 205 206 207 208 /*************************************************************************** 209 * Tests for specific bug reports 210 **************************************************************************/ 211 212 @Test public void test_rt29833_mouse_select_upwards() { 213 sm.setCellSelectionEnabled(false); 214 sm.setSelectionMode(SelectionMode.MULTIPLE); 215 216 sm.clearAndSelect(9); 217 218 // select all from 9 - 7 219 VirtualFlowTestUtils.clickOnRow(tableView, 7, KeyModifier.SHIFT); 220 assertTrue(debug(), isSelected(7,8,9)); 221 222 // select all from 9 - 7 - 5 223 VirtualFlowTestUtils.clickOnRow(tableView, 5, KeyModifier.SHIFT); 224 assertTrue(debug(),isSelected(5,6,7,8,9)); 225 } 226 227 @Test public void test_rt29833_mouse_select_downwards() { 228 sm.setCellSelectionEnabled(false); 229 sm.setSelectionMode(SelectionMode.MULTIPLE); 230 231 sm.clearAndSelect(5); 232 233 // select all from 5 - 7 234 VirtualFlowTestUtils.clickOnRow(tableView, 7, KeyModifier.SHIFT); 235 assertTrue(debug(), isSelected(5,6,7)); 236 237 // select all from 5 - 7 - 9 238 VirtualFlowTestUtils.clickOnRow(tableView, 9, KeyModifier.SHIFT); 239 assertTrue(debug(),isSelected(5,6,7,8,9)); 240 } 241 242 private int rt30394_count = 0; 243 // @Ignore("Ignoring due to RT-37166") 244 @Test public void test_rt30394() { 245 sm.setCellSelectionEnabled(false); 246 sm.setSelectionMode(SelectionMode.MULTIPLE); 247 sm.clearSelection(); 248 249 final TableFocusModel fm = tableView.getFocusModel(); 250 fm.focus(-1); 251 252 fm.focusedIndexProperty().addListener((observable, oldValue, newValue) -> { 253 rt30394_count++; 254 assertEquals(0, fm.getFocusedIndex()); 255 }); 256 257 // test pre-conditions 258 assertEquals(0,rt30394_count); 259 assertFalse(fm.isFocused(0)); 260 261 // select the first row with the shift key held down. The focus event 262 // should only fire once - for focus on 0 (never -1 as this bug shows). 263 VirtualFlowTestUtils.clickOnRow(tableView, 0, KeyModifier.SHIFT); 264 Toolkit.getToolkit().firePulse(); 265 assertEquals(1, rt30394_count); 266 assertTrue(fm.isFocused(0)); 267 } 268 269 @Test public void test_rt32119() { 270 sm.setSelectionMode(SelectionMode.MULTIPLE); 271 sm.clearSelection(); 272 273 // select rows 2, 3, and 4 274 VirtualFlowTestUtils.clickOnRow(tableView, 2); 275 VirtualFlowTestUtils.clickOnRow(tableView, 4, KeyModifier.SHIFT); 276 assertFalse(sm.isSelected(1)); 277 assertTrue(sm.isSelected(2)); 278 assertTrue(sm.isSelected(3)); 279 assertTrue(sm.isSelected(4)); 280 assertFalse(sm.isSelected(5)); 281 282 // now shift click on the 2nd row - this should make only row 2 be 283 // selected. The bug is that row 4 remains selected also. 284 VirtualFlowTestUtils.clickOnRow(tableView, 2, KeyModifier.SHIFT); 285 assertFalse(sm.isSelected(1)); 286 assertTrue(sm.isSelected(2)); 287 assertFalse(sm.isSelected(3)); 288 assertFalse(sm.isSelected(4)); 289 assertFalse(sm.isSelected(5)); 290 } 291 292 @Test public void test_rt31020() { 293 sm.setSelectionMode(SelectionMode.MULTIPLE); 294 sm.clearSelection(); 295 296 // set all the columns to be very narrow (so the mouse click happens 297 // to the right of them all, out in no-mans land 298 tableView.setMinWidth(200); 299 tableView.setPrefWidth(200); 300 tableView.getColumns().clear(); 301 col0.setMaxWidth(10); 302 tableView.getColumns().add(col0); 303 304 // select rows 1, 2, 3, 4, and 5 305 VirtualFlowTestUtils.clickOnRow(tableView, 1, true); 306 VirtualFlowTestUtils.clickOnRow(tableView, 5, true, KeyModifier.SHIFT); 307 assertTrue(sm.isSelected(1)); 308 assertTrue(sm.isSelected(2)); 309 assertTrue(sm.isSelected(3)); 310 assertTrue(sm.isSelected(4)); 311 assertTrue(sm.isSelected(5)); 312 } 313 314 @Test public void test_rt21444_up_cell() { 315 final int items = 8; 316 root.getChildren().clear(); 317 for (int i = 0; i < items; i++) { 318 root.getChildren().add(new TreeItem<>("Row " + i)); 319 } 320 321 final int selectRow = 3; 322 323 tableView.setShowRoot(false); 324 final MultipleSelectionModel<TreeItem<String>> sm = tableView.getSelectionModel(); 325 sm.setSelectionMode(SelectionMode.MULTIPLE); 326 sm.clearAndSelect(selectRow); 327 328 assertEquals(selectRow, sm.getSelectedIndex()); 329 assertEquals("Row 3", sm.getSelectedItem().getValue()); 330 331 VirtualFlowTestUtils.clickOnRow(tableView, selectRow - 1, KeyModifier.SHIFT); 332 assertEquals(2, sm.getSelectedItems().size()); 333 assertEquals("Row 2", sm.getSelectedItem().getValue()); 334 assertEquals("Row 2", sm.getSelectedItems().get(0).getValue()); 335 } 336 337 @Test public void test_rt21444_down_cell() { 338 final int items = 8; 339 root.getChildren().clear(); 340 for (int i = 0; i < items; i++) { 341 root.getChildren().add(new TreeItem<>("Row " + i)); 342 } 343 344 final int selectRow = 3; 345 346 tableView.setShowRoot(false); 347 final MultipleSelectionModel<TreeItem<String>> sm = tableView.getSelectionModel(); 348 sm.setSelectionMode(SelectionMode.MULTIPLE); 349 sm.clearAndSelect(selectRow); 350 351 assertEquals(selectRow, sm.getSelectedIndex()); 352 assertEquals("Row 3", sm.getSelectedItem().getValue()); 353 354 VirtualFlowTestUtils.clickOnRow(tableView, selectRow + 1, KeyModifier.SHIFT); 355 assertEquals("Row 4", sm.getSelectedItem().getValue()); 356 } 357 358 @Test public void test_rt21444_up_row() { 359 final int items = 8; 360 root.getChildren().clear(); 361 for (int i = 0; i < items; i++) { 362 root.getChildren().add(new TreeItem<>("Row " + i)); 363 } 364 365 final int selectRow = 3; 366 367 tableView.setShowRoot(false); 368 final MultipleSelectionModel<TreeItem<String>> sm = tableView.getSelectionModel(); 369 sm.setSelectionMode(SelectionMode.MULTIPLE); 370 sm.clearAndSelect(selectRow); 371 372 assertEquals(selectRow, sm.getSelectedIndex()); 373 assertEquals("Row 3", sm.getSelectedItem().getValue()); 374 375 VirtualFlowTestUtils.clickOnRow(tableView, selectRow - 1, true, KeyModifier.SHIFT); 376 assertEquals(2, sm.getSelectedItems().size()); 377 assertEquals("Row 2", sm.getSelectedItem().getValue()); 378 assertEquals("Row 2", sm.getSelectedItems().get(0).getValue()); 379 } 380 381 @Test public void test_rt21444_down_row() { 382 final int items = 8; 383 root.getChildren().clear(); 384 for (int i = 0; i < items; i++) { 385 root.getChildren().add(new TreeItem<>("Row " + i)); 386 } 387 388 final int selectRow = 3; 389 390 tableView.setShowRoot(false); 391 final MultipleSelectionModel<TreeItem<String>> sm = tableView.getSelectionModel(); 392 sm.setSelectionMode(SelectionMode.MULTIPLE); 393 sm.clearAndSelect(selectRow); 394 395 assertEquals(selectRow, sm.getSelectedIndex()); 396 assertEquals("Row 3", sm.getSelectedItem().getValue()); 397 398 VirtualFlowTestUtils.clickOnRow(tableView, selectRow + 1, true, KeyModifier.SHIFT); 399 assertEquals("Row 4", sm.getSelectedItem().getValue()); 400 } 401 402 @Test public void test_rt32560_cell() { 403 final int items = 8; 404 root.getChildren().clear(); 405 for (int i = 0; i < items; i++) { 406 root.getChildren().add(new TreeItem<>("Row " + i)); 407 } 408 409 final MultipleSelectionModel sm = tableView.getSelectionModel(); 410 sm.setSelectionMode(SelectionMode.MULTIPLE); 411 sm.clearAndSelect(0); 412 413 assertEquals(0, sm.getSelectedIndex()); 414 assertEquals(root, sm.getSelectedItem()); 415 assertEquals(0, fm.getFocusedIndex()); 416 417 VirtualFlowTestUtils.clickOnRow(tableView, 5, KeyModifier.SHIFT); 418 assertEquals(5, sm.getSelectedIndex()); 419 assertEquals(5, fm.getFocusedIndex()); 420 assertEquals(6, sm.getSelectedItems().size()); 421 422 VirtualFlowTestUtils.clickOnRow(tableView, 0, KeyModifier.SHIFT); 423 assertEquals(0, sm.getSelectedIndex()); 424 assertEquals(0, fm.getFocusedIndex()); 425 assertEquals(1, sm.getSelectedItems().size()); 426 } 427 428 @Test public void test_rt32560_row() { 429 final int items = 8; 430 root.getChildren().clear(); 431 for (int i = 0; i < items; i++) { 432 root.getChildren().add(new TreeItem<>("Row " + i)); 433 } 434 435 // StageLoader sl = new StageLoader(tableView); 436 437 tableView.setShowRoot(true); 438 final MultipleSelectionModel sm = tableView.getSelectionModel(); 439 sm.setSelectionMode(SelectionMode.MULTIPLE); 440 sm.clearAndSelect(0); 441 442 assertEquals(0, sm.getSelectedIndex()); 443 assertEquals(root, sm.getSelectedItem()); 444 assertEquals(0, fm.getFocusedIndex()); 445 446 VirtualFlowTestUtils.clickOnRow(tableView, 5, true, KeyModifier.SHIFT); 447 assertEquals(5, sm.getSelectedIndex()); 448 assertEquals(5, fm.getFocusedIndex()); 449 assertEquals(sm.getSelectedItems().toString(), 6, sm.getSelectedItems().size()); 450 451 VirtualFlowTestUtils.clickOnRow(tableView, 0, true, KeyModifier.SHIFT); 452 assertEquals(0, sm.getSelectedIndex()); 453 assertEquals(0, fm.getFocusedIndex()); 454 assertEquals(debug(), 1, sm.getSelectedItems().size()); 455 456 // sl.dispose(); 457 } 458 459 @Test public void test_rt_32963() { 460 final int items = 8; 461 root.getChildren().clear(); 462 root.setExpanded(true); 463 for (int i = 0; i < items; i++) { 464 root.getChildren().add(new TreeItem<>("Row " + i)); 465 } 466 tableView.setRoot(root); 467 468 tableView.setShowRoot(true); 469 final MultipleSelectionModel sm = tableView.getSelectionModel(); 470 sm.setSelectionMode(SelectionMode.MULTIPLE); 471 sm.clearAndSelect(0); 472 473 assertEquals(9, tableView.getExpandedItemCount()); 474 475 assertEquals(0, sm.getSelectedIndex()); 476 assertEquals(0, fm.getFocusedIndex()); 477 assertEquals(root, sm.getSelectedItem()); 478 assertEquals(1, sm.getSelectedItems().size()); 479 480 VirtualFlowTestUtils.clickOnRow(tableView, 5, KeyModifier.SHIFT); 481 assertEquals("Actual selected index: " + sm.getSelectedIndex(), 5, sm.getSelectedIndex()); 482 assertEquals("Actual focused index: " + fm.getFocusedIndex(), 5, fm.getFocusedIndex()); 483 assertTrue("Selected indices: " + sm.getSelectedIndices(), sm.getSelectedIndices().contains(0)); 484 assertTrue("Selected items: " + sm.getSelectedItems(), sm.getSelectedItems().contains(root)); 485 assertEquals(6, sm.getSelectedItems().size()); 486 } 487 488 @Ignore("Test doesn't work - mouse event not firing as expected") 489 @Test public void test_rt_33101() { 490 final int items = 8; 491 root.setValue("New Root"); 492 root.getChildren().clear(); 493 root.setExpanded(true); 494 for (int i = 0; i < items; i++) { 495 root.getChildren().add(new TreeItem<>("Row " + i)); 496 } 497 tableView.setRoot(root); 498 499 StageLoader sl = new StageLoader(tableView); 500 501 tableView.setShowRoot(true); 502 final MultipleSelectionModel sm = tableView.getSelectionModel(); 503 sm.setSelectionMode(SelectionMode.MULTIPLE); 504 sm.clearAndSelect(0); 505 506 TreeTableRow rootRow = (TreeTableRow) VirtualFlowTestUtils.getCell(tableView, 0); 507 Node disclosureNode = rootRow.getDisclosureNode(); 508 509 assertTrue(root.isExpanded()); 510 assertEquals("New Root", rootRow.getTreeItem().getValue()); 511 assertNotNull(disclosureNode); 512 assertTrue(disclosureNode.isVisible()); 513 assertTrue(disclosureNode.getScene() != null); 514 assertEquals(9, tableView.getExpandedItemCount()); 515 516 MouseEventFirer mouse = new MouseEventFirer(disclosureNode); 517 mouse.fireMousePressAndRelease(); 518 assertFalse(root.isExpanded()); 519 assertEquals(1, tableView.getExpandedItemCount()); 520 521 mouse.fireMousePressAndRelease(); 522 assertTrue(root.isExpanded()); 523 assertEquals(9, tableView.getExpandedItemCount()); 524 525 mouse.dispose(); 526 sl.dispose(); 527 } 528 529 private int rt_30626_count = 0; 530 @Test public void test_rt_30626() { 531 final int items = 8; 532 root.getChildren().clear(); 533 root.setExpanded(true); 534 for (int i = 1; i < items; i++) { 535 root.getChildren().add(new TreeItem<>("Row " + i)); 536 } 537 tableView.setRoot(root); 538 539 tableView.setShowRoot(true); 540 final MultipleSelectionModel sm = tableView.getSelectionModel(); 541 sm.setSelectionMode(SelectionMode.MULTIPLE); 542 sm.clearAndSelect(0); 543 544 tableView.getSelectionModel().getSelectedItems().addListener((ListChangeListener) c -> { 545 while (c.next()) { 546 rt_30626_count++; 547 } 548 }); 549 550 Cell cell = VirtualFlowTestUtils.getCell(tableView, 1, 0); 551 MouseEventFirer mouse = new MouseEventFirer(cell); 552 553 assertEquals(0, rt_30626_count); 554 mouse.fireMousePressAndRelease(); 555 assertEquals(1, rt_30626_count); 556 557 mouse.fireMousePressAndRelease(); 558 assertEquals(1, rt_30626_count); 559 } 560 561 @Test public void test_rt_33897_rowSelection() { 562 final int items = 8; 563 root.getChildren().clear(); 564 root.setExpanded(true); 565 for (int i = 0; i < items; i++) { 566 root.getChildren().add(new TreeItem<>("Row " + i)); 567 } 568 tableView.setRoot(root); 569 570 final TreeTableView.TreeTableViewSelectionModel<String> sm = tableView.getSelectionModel(); 571 sm.setSelectionMode(SelectionMode.MULTIPLE); 572 sm.setCellSelectionEnabled(false); 573 574 VirtualFlowTestUtils.clickOnRow(tableView, 1); 575 assertEquals(1, sm.getSelectedCells().size()); 576 577 TreeTablePosition pos = sm.getSelectedCells().get(0); 578 assertEquals(1, pos.getRow()); 579 assertNotNull(pos.getTableColumn()); 580 } 581 582 @Test public void test_rt_33897_cellSelection() { 583 final int items = 8; 584 root.getChildren().clear(); 585 root.setExpanded(true); 586 for (int i = 0; i < items; i++) { 587 root.getChildren().add(new TreeItem<>("Row " + i)); 588 } 589 tableView.setRoot(root); 590 591 final TreeTableView.TreeTableViewSelectionModel<String> sm = tableView.getSelectionModel(); 592 sm.setSelectionMode(SelectionMode.MULTIPLE); 593 sm.setCellSelectionEnabled(true); 594 595 VirtualFlowTestUtils.clickOnRow(tableView, 1); 596 assertEquals(1, sm.getSelectedCells().size()); 597 598 TreeTablePosition pos = sm.getSelectedCells().get(0); 599 assertEquals(1, pos.getRow()); 600 assertNotNull(pos.getTableColumn()); 601 } 602 603 @Test public void test_rt_34649() { 604 final int items = 8; 605 root.getChildren().clear(); 606 root.setExpanded(true); 607 for (int i = 0; i < items; i++) { 608 root.getChildren().add(new TreeItem<>("Row " + i)); 609 } 610 tableView.setRoot(root); 611 612 final MultipleSelectionModel sm = tableView.getSelectionModel(); 613 final FocusModel fm = tableView.getFocusModel(); 614 sm.setSelectionMode(SelectionMode.SINGLE); 615 616 assertFalse(sm.isSelected(4)); 617 assertFalse(fm.isFocused(4)); 618 VirtualFlowTestUtils.clickOnRow(tableView, 4, true, KeyModifier.getShortcutKey()); 619 assertTrue(sm.isSelected(4)); 620 assertTrue(fm.isFocused(4)); 621 622 VirtualFlowTestUtils.clickOnRow(tableView, 4, true, KeyModifier.getShortcutKey()); 623 assertFalse(sm.isSelected(4)); 624 assertTrue(fm.isFocused(4)); 625 } 626 627 @Test public void test_rt_35338() { 628 root.getChildren().clear(); 629 tableView.setRoot(root); 630 tableView.getColumns().setAll(col0); 631 632 col0.setWidth(20); 633 tableView.setMinWidth(1000); 634 tableView.setMinWidth(1000); 635 636 TreeTableRow row = (TreeTableRow) VirtualFlowTestUtils.getCell(tableView, 4); 637 assertNotNull(row); 638 assertNull(row.getItem()); 639 assertEquals(4, row.getIndex()); 640 641 MouseEventFirer mouse = new MouseEventFirer(row); 642 mouse.fireMousePressAndRelease(1, 100, 10); 643 mouse.dispose(); 644 } 645 646 @Test public void test_rt_36509() { 647 final int items = 8; 648 root.getChildren().clear(); 649 root.setExpanded(false); 650 for (int i = 0; i < items; i++) { 651 root.getChildren().add(new TreeItem<>("Row " + i)); 652 } 653 tableView.setRoot(root); 654 655 // expand 656 assertFalse(root.isExpanded()); 657 VirtualFlowTestUtils.clickOnRow(tableView, 0, 2); 658 assertTrue(root.isExpanded()); 659 660 // collapse 661 VirtualFlowTestUtils.clickOnRow(tableView, 0, 2); 662 assertFalse(root.isExpanded()); 663 664 // expand again 665 VirtualFlowTestUtils.clickOnRow(tableView, 0, 2); 666 assertTrue(root.isExpanded()); 667 } 668 669 @Test public void test_rt_37069() { 670 final int items = 8; 671 root.getChildren().clear(); 672 root.setExpanded(false); 673 for (int i = 0; i < items; i++) { 674 root.getChildren().add(new TreeItem<>("Row " + i)); 675 } 676 tableView.setRoot(root); 677 tableView.setFocusTraversable(false); 678 679 Button btn = new Button("Button"); 680 VBox vbox = new VBox(btn, tableView); 681 682 StageLoader sl = new StageLoader(vbox); 683 sl.getStage().requestFocus(); 684 btn.requestFocus(); 685 Toolkit.getToolkit().firePulse(); 686 Scene scene = sl.getStage().getScene(); 687 688 assertTrue(btn.isFocused()); 689 assertFalse(tableView.isFocused()); 690 691 ScrollBar vbar = VirtualFlowTestUtils.getVirtualFlowVerticalScrollbar(tableView); 692 MouseEventFirer mouse = new MouseEventFirer(vbar); 693 mouse.fireMousePressAndRelease(); 694 695 assertTrue(btn.isFocused()); 696 assertFalse(tableView.isFocused()); 697 698 sl.dispose(); 699 } 700 701 @Test public void test_rt_38306_selectFirstRow() { 702 test_rt_38306(false); 703 } 704 705 @Test public void test_rt_38306_selectFirstTwoRows() { 706 test_rt_38306(true); 707 } 708 709 private void test_rt_38306(boolean selectTwoRows) { 710 TreeItem<Person> root = new TreeItem<>(); 711 root.getChildren().addAll( 712 new TreeItem<>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 713 new TreeItem<>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 714 new TreeItem<>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 715 new TreeItem<>(new Person("Emma", "Jones", "emma.jones@example.com")), 716 new TreeItem<>(new Person("Michael", "Brown", "michael.brown@example.com")) 717 ); 718 719 TreeTableView<Person> table = new TreeTableView<>(); 720 table.setRoot(root); 721 root.setExpanded(true); 722 table.setShowRoot(false); 723 724 TreeTableView.TreeTableViewSelectionModel sm = table.getSelectionModel(); 725 sm.setCellSelectionEnabled(true); 726 sm.setSelectionMode(SelectionMode.MULTIPLE); 727 728 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 729 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 730 731 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 732 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 733 734 TreeTableColumn emailCol = new TreeTableColumn("Email"); 735 emailCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("email")); 736 737 table.getColumns().addAll(firstNameCol, lastNameCol, emailCol); 738 739 sm.select(0, firstNameCol); 740 741 assertTrue(sm.isSelected(0, firstNameCol)); 742 assertEquals(1, sm.getSelectedCells().size()); 743 744 TreeTableCell cell_0_0 = (TreeTableCell) VirtualFlowTestUtils.getCell(table, 0, 0); 745 TreeTableCell cell_0_1 = (TreeTableCell) VirtualFlowTestUtils.getCell(table, 0, 1); 746 TreeTableCell cell_0_2 = (TreeTableCell) VirtualFlowTestUtils.getCell(table, 0, 2); 747 748 TreeTableCell cell_1_0 = (TreeTableCell) VirtualFlowTestUtils.getCell(table, 1, 0); 749 TreeTableCell cell_1_1 = (TreeTableCell) VirtualFlowTestUtils.getCell(table, 1, 1); 750 TreeTableCell cell_1_2 = (TreeTableCell) VirtualFlowTestUtils.getCell(table, 1, 2); 751 752 MouseEventFirer mouse = selectTwoRows ? 753 new MouseEventFirer(cell_1_2) : new MouseEventFirer(cell_0_2); 754 755 mouse.fireMousePressAndRelease(KeyModifier.SHIFT); 756 757 assertTrue(sm.isSelected(0, firstNameCol)); 758 assertTrue(sm.isSelected(0, lastNameCol)); 759 assertTrue(sm.isSelected(0, emailCol)); 760 761 if (selectTwoRows) { 762 assertTrue(sm.isSelected(1, firstNameCol)); 763 assertTrue(sm.isSelected(1, lastNameCol)); 764 assertTrue(sm.isSelected(1, emailCol)); 765 } 766 767 assertEquals(selectTwoRows ? 6 : 3, sm.getSelectedCells().size()); 768 769 assertTrue(cell_0_0.isSelected()); 770 assertTrue(cell_0_1.isSelected()); 771 assertTrue(cell_0_2.isSelected()); 772 773 if (selectTwoRows) { 774 assertTrue(cell_1_0.isSelected()); 775 assertTrue(cell_1_1.isSelected()); 776 assertTrue(cell_1_2.isSelected()); 777 } 778 } 779 780 @Test public void test_rt_38464_rowSelection() { 781 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 782 new TreeItem<>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 783 new TreeItem<>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 784 new TreeItem<>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 785 new TreeItem<>(new Person("Emma", "Jones", "emma.jones@example.com")), 786 new TreeItem<>(new Person("Michael", "Brown", "michael.brown@example.com"))); 787 788 TreeTableView<Person> table = new TreeTableView<>(); 789 790 TreeItem<Person> root = new TreeItem<Person>(new Person("Root", null, null)); 791 root.setExpanded(true); 792 table.setRoot(root); 793 table.setShowRoot(false); 794 root.getChildren().setAll(persons); 795 796 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 797 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 798 799 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 800 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 801 802 TreeTableColumn emailCol = new TreeTableColumn("Email"); 803 emailCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("email")); 804 805 table.getColumns().addAll(firstNameCol, lastNameCol, emailCol); 806 807 sm = table.getSelectionModel(); 808 sm.setCellSelectionEnabled(false); 809 sm.setSelectionMode(SelectionMode.MULTIPLE); 810 811 sm.clearSelection(); 812 sm.select(0, lastNameCol); 813 814 assertTrue(sm.isSelected(0, lastNameCol)); 815 assertEquals(1, sm.getSelectedCells().size()); 816 817 TreeTableCell cell_4_2 = (TreeTableCell) VirtualFlowTestUtils.getCell(table, 4, 1); 818 819 MouseEventFirer mouse = new MouseEventFirer(cell_4_2); 820 mouse.fireMousePressAndRelease(KeyModifier.SHIFT); 821 822 // we are in row selection mode, so all cells in the selected rows should 823 // be selected. We test this per-cell, but also per-row. 824 for (int row = 0; row < 5; row++) { 825 // test that the selection model is accurate 826 assertTrue(sm.isSelected(row, firstNameCol)); 827 assertTrue(sm.isSelected(row, lastNameCol)); 828 assertTrue(sm.isSelected(row, emailCol)); 829 assertTrue(sm.isSelected(row)); 830 831 // and assert that the visuals are accurate 832 // (TableCells should not be selected, but TableRows should be) 833 for (int column = 0; column < 3; column++) { 834 if (row == 4 && column == 2) { 835 // bizarrely cell (4,2), i.e. the bottom-right cell consisting 836 // of Michael Brown's email address, doesn't exist. 837 continue; 838 } 839 TreeTableCell cell = (TreeTableCell) VirtualFlowTestUtils.getCell(table, row, column); 840 assertFalse("cell[row: " + row + ", column: " + column + "] is selected, but shouldn't be", cell.isSelected()); 841 } 842 TreeTableRow cell = (TreeTableRow) VirtualFlowTestUtils.getCell(table, row); 843 assertTrue(cell.isSelected()); 844 } 845 } 846 847 @Test public void test_rt_38464_cellSelection() { 848 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 849 new TreeItem<>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 850 new TreeItem<>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 851 new TreeItem<>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 852 new TreeItem<>(new Person("Emma", "Jones", "emma.jones@example.com")), 853 new TreeItem<>(new Person("Michael", "Brown", "michael.brown@example.com"))); 854 855 TreeTableView<Person> table = new TreeTableView<>(); 856 857 TreeItem<Person> root = new TreeItem<>(new Person("Root", null, null)); 858 root.setExpanded(true); 859 table.setRoot(root); 860 table.setShowRoot(false); 861 root.getChildren().setAll(persons); 862 863 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 864 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 865 866 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 867 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 868 869 TreeTableColumn emailCol = new TreeTableColumn("Email"); 870 emailCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("email")); 871 872 table.getColumns().addAll(firstNameCol, lastNameCol, emailCol); 873 874 sm = table.getSelectionModel(); 875 sm.setCellSelectionEnabled(true); 876 sm.setSelectionMode(SelectionMode.MULTIPLE); 877 878 sm.clearSelection(); 879 sm.select(0, emailCol); 880 table.getFocusModel().focus(0, emailCol); 881 882 assertTrue(sm.isSelected(0, emailCol)); 883 assertEquals(1, sm.getSelectedCells().size()); 884 885 TreeTableCell cell_4_2 = (TreeTableCell) VirtualFlowTestUtils.getCell(table, 4, 2); 886 assertEquals(emailCol, cell_4_2.getTableColumn()); 887 888 new MouseEventFirer(cell_4_2).fireMousePressAndRelease(KeyModifier.SHIFT); 889 890 for (int row = 0; row < 5; row++) { 891 // test that the selection model is accurate 892 assertFalse(sm.isSelected(row, firstNameCol)); 893 assertFalse(sm.isSelected(row, lastNameCol)); 894 assertTrue(sm.isSelected(row, emailCol)); 895 assertFalse(sm.isSelected(row)); 896 897 // and assert that the visuals are accurate 898 // (some TableCells should be selected, but TableRows should not be) 899 for (int column = 0; column < 3; column++) { 900 if (row == 4 && column == 2) { 901 // bizarrely cell (4,2), i.e. the bottom-right cell consisting 902 // of Michael Brown's email address, doesn't exist. 903 continue; 904 } 905 TreeTableCell cell = (TreeTableCell) VirtualFlowTestUtils.getCell(table, row, column); 906 assertEquals(column == 2 ? true : false, cell.isSelected()); 907 } 908 TreeTableRow cell = (TreeTableRow) VirtualFlowTestUtils.getCell(table, row); 909 assertFalse(cell.isSelected()); 910 } 911 } 912 913 @Test public void test_rt_38464_selectedColumnChangesWhenCellsInRowClicked_cellSelection_singleSelection() { 914 test_rt_38464_selectedColumnChangesWhenCellsInRowClicked(true, true); 915 } 916 917 @Test public void test_rt_38464_selectedColumnChangesWhenCellsInRowClicked_cellSelection_multipleSelection() { 918 test_rt_38464_selectedColumnChangesWhenCellsInRowClicked(true, false); 919 } 920 921 @Test public void test_rt_38464_selectedColumnChangesWhenCellsInRowClicked_rowSelection_singleSelection() { 922 test_rt_38464_selectedColumnChangesWhenCellsInRowClicked(false, true); 923 } 924 925 @Test public void test_rt_38464_selectedColumnChangesWhenCellsInRowClicked_rowSelection_multipleSelection() { 926 test_rt_38464_selectedColumnChangesWhenCellsInRowClicked(false, false); 927 } 928 929 private void test_rt_38464_selectedColumnChangesWhenCellsInRowClicked(boolean cellSelection, boolean singleSelection) { 930 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 931 new TreeItem<>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 932 new TreeItem<>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 933 new TreeItem<>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 934 new TreeItem<>(new Person("Emma", "Jones", "emma.jones@example.com")), 935 new TreeItem<>(new Person("Michael", "Brown", "michael.brown@example.com"))); 936 937 TreeTableView<Person> table = new TreeTableView<>(); 938 939 TreeItem<Person> root = new TreeItem<Person>(new Person("Root", null, null)); 940 root.setExpanded(true); 941 table.setRoot(root); 942 table.setShowRoot(false); 943 root.getChildren().setAll(persons); 944 945 TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); 946 firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("firstName")); 947 948 TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); 949 lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("lastName")); 950 951 TreeTableColumn emailCol = new TreeTableColumn("Email"); 952 emailCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person, String>("email")); 953 954 table.getColumns().addAll(firstNameCol, lastNameCol, emailCol); 955 956 TreeTableView.TreeTableViewSelectionModel<Person> sm = table.getSelectionModel(); 957 sm.setCellSelectionEnabled(cellSelection); 958 sm.setSelectionMode(singleSelection ? SelectionMode.SINGLE : SelectionMode.MULTIPLE); 959 960 TreeTableCell cell_0_0 = (TreeTableCell) VirtualFlowTestUtils.getCell(table, 0, 0); 961 TreeTableCell cell_0_1 = (TreeTableCell) VirtualFlowTestUtils.getCell(table, 0, 1); 962 TreeTableCell cell_0_2 = (TreeTableCell) VirtualFlowTestUtils.getCell(table, 0, 2); 963 964 sm.clearSelection(); 965 966 // click on cell (0,0). 967 new MouseEventFirer(cell_0_0).fireMousePressAndRelease(); 968 969 if (cellSelection) { 970 // Because we are in cell selection mode, this has the effect of 971 // selecting just the one cell. 972 assertFalse(sm.isSelected(0)); 973 assertTrue(sm.isSelected(0, firstNameCol)); 974 assertFalse(sm.isSelected(0, lastNameCol)); 975 assertFalse(sm.isSelected(0, emailCol)); 976 assertEquals(1, sm.getSelectedCells().size()); 977 assertEquals(0, sm.getSelectedCells().get(0).getRow()); 978 assertEquals(firstNameCol, sm.getSelectedCells().get(0).getTableColumn()); 979 } else { 980 // Because we are in row selection mode, this has 981 // the effect of selecting all cells and the backing row. However, the 982 // selected cell will be (0, firstNameCol) only 983 assertTrue(sm.isSelected(0)); 984 assertTrue(sm.isSelected(0, firstNameCol)); 985 assertTrue(sm.isSelected(0, lastNameCol)); 986 assertTrue(sm.isSelected(0, emailCol)); 987 assertEquals(1, sm.getSelectedCells().size()); 988 assertEquals(0, sm.getSelectedCells().get(0).getRow()); 989 assertEquals(firstNameCol, sm.getSelectedCells().get(0).getTableColumn()); 990 } 991 992 // click on cell (0,1). 993 new MouseEventFirer(cell_0_1).fireMousePressAndRelease(); 994 995 if (cellSelection) { 996 // Everything should remain the same, except the 997 // column of the single selected cell should change to lastNameCol. 998 assertFalse(sm.isSelected(0)); 999 assertFalse(sm.isSelected(0, firstNameCol)); 1000 assertTrue(sm.isSelected(0, lastNameCol)); 1001 assertFalse(sm.isSelected(0, emailCol)); 1002 assertEquals(1, sm.getSelectedCells().size()); 1003 TreeTablePosition<?,?> cell = sm.getSelectedCells().get(0); 1004 assertEquals(0, cell.getRow()); 1005 assertEquals(lastNameCol, cell.getTableColumn()); 1006 } else { 1007 // Everything should remain the same, except the 1008 // column of the single selected cell should change to lastNameCol. 1009 assertTrue(sm.isSelected(0)); 1010 assertTrue(sm.isSelected(0, firstNameCol)); 1011 assertTrue(sm.isSelected(0, lastNameCol)); 1012 assertTrue(sm.isSelected(0, emailCol)); 1013 assertEquals(1, sm.getSelectedCells().size()); 1014 TreeTablePosition<?,?> cell = sm.getSelectedCells().get(0); 1015 assertEquals(0, cell.getRow()); 1016 assertEquals(lastNameCol, cell.getTableColumn()); 1017 } 1018 } 1019 }