diff --git a/modules/controls/src/main/java/javafx/scene/control/TableView.java b/modules/controls/src/main/java/javafx/scene/control/TableView.java --- a/modules/controls/src/main/java/javafx/scene/control/TableView.java +++ b/modules/controls/src/main/java/javafx/scene/control/TableView.java @@ -2686,7 +2686,9 @@ final int endChangeIndex = selectedCellsMap.indexOf(new TablePosition<>(tableView, maxRow, (TableColumn)maxColumn)); if (startChangeIndex > -1 && endChangeIndex > -1) { - ListChangeListener.Change c = new NonIterableChange.SimpleAddChange<>(startChangeIndex, endChangeIndex + 1, selectedCellsSeq); + final int startIndex = Math.min(startChangeIndex, endChangeIndex); + final int endIndex = Math.max(startChangeIndex, endChangeIndex); + ListChangeListener.Change c = new NonIterableChange.SimpleAddChange<>(startIndex, endIndex + 1, selectedCellsSeq); handleSelectedCellsListChangeEvent(c); } } diff --git a/modules/controls/src/main/java/javafx/scene/control/TreeTableView.java b/modules/controls/src/main/java/javafx/scene/control/TreeTableView.java --- a/modules/controls/src/main/java/javafx/scene/control/TreeTableView.java +++ b/modules/controls/src/main/java/javafx/scene/control/TreeTableView.java @@ -2939,7 +2939,10 @@ final int endChangeIndex = selectedCellsMap.indexOf(new TreeTablePosition<>(treeTableView, maxRow, (TreeTableColumn)maxColumn)); if (startChangeIndex > -1 && endChangeIndex > -1) { - handleSelectedCellsListChangeEvent(new NonIterableChange.SimpleAddChange<>(startChangeIndex, endChangeIndex + 1, selectedCellsSeq)); + final int startIndex = Math.min(startChangeIndex, endChangeIndex); + final int endIndex = Math.max(startChangeIndex, endChangeIndex); + ListChangeListener.Change c = new NonIterableChange.SimpleAddChange<>(startIndex, endIndex + 1, selectedCellsSeq); + handleSelectedCellsListChangeEvent(c); } } diff --git a/modules/controls/src/test/java/javafx/scene/control/TableViewTest.java b/modules/controls/src/test/java/javafx/scene/control/TableViewTest.java --- a/modules/controls/src/test/java/javafx/scene/control/TableViewTest.java +++ b/modules/controls/src/test/java/javafx/scene/control/TableViewTest.java @@ -4791,4 +4791,72 @@ Thread.currentThread().setUncaughtExceptionHandler(exceptionHandler); } } + + private int test_rt_39842_count = 0; + @Test public void test_rt_39842_selectLeftDown() { + test_rt_39842(true, false); + } + + @Test public void test_rt_39842_selectLeftUp() { + test_rt_39842(true, true); + } + + @Test public void test_rt_39842_selectRightDown() { + test_rt_39842(false, false); + } + + @Test public void test_rt_39842_selectRightUp() { + test_rt_39842(false, true); + } + + private void test_rt_39842(boolean selectToLeft, boolean selectUpwards) { + test_rt_39842_count = 0; + + TableColumn firstNameCol = new TableColumn("First Name"); + firstNameCol.setCellValueFactory(new PropertyValueFactory("firstName")); + + TableColumn lastNameCol = new TableColumn("Last Name"); + lastNameCol.setCellValueFactory(new PropertyValueFactory("lastName")); + + TableView table = new TableView<>(); + table.setItems(personTestData); + table.getColumns().addAll(firstNameCol, lastNameCol); + + sm = table.getSelectionModel(); + sm.setCellSelectionEnabled(true); + sm.setSelectionMode(SelectionMode.MULTIPLE); + sm.getSelectedCells().addListener((ListChangeListener) c -> test_rt_39842_count++); + + StageLoader sl = new StageLoader(table); + + assertEquals(0, test_rt_39842_count); + + if (selectToLeft) { + if (selectUpwards) { + sm.selectRange(3, lastNameCol, 0, firstNameCol); + } else { + sm.selectRange(0, lastNameCol, 3, firstNameCol); + } + } else { + if (selectUpwards) { + sm.selectRange(3, firstNameCol, 0, lastNameCol); + } else { + sm.selectRange(0, firstNameCol, 3, lastNameCol); + } + } + + // test model state + assertEquals(8, sm.getSelectedCells().size()); + assertEquals(1, test_rt_39842_count); + + // test visual state + for (int row = 0; row <= 3; row++) { + for (int column = 0; column <= 1; column++) { + IndexedCell cell = VirtualFlowTestUtils.getCell(table, row, column); + assertTrue(cell.isSelected()); + } + } + + sl.dispose(); + } } diff --git a/modules/controls/src/test/java/javafx/scene/control/TreeTableViewTest.java b/modules/controls/src/test/java/javafx/scene/control/TreeTableViewTest.java --- a/modules/controls/src/test/java/javafx/scene/control/TreeTableViewTest.java +++ b/modules/controls/src/test/java/javafx/scene/control/TreeTableViewTest.java @@ -5185,4 +5185,81 @@ Thread.currentThread().setUncaughtExceptionHandler(exceptionHandler); } } + + private int test_rt_39842_count = 0; + @Test public void test_rt_39842_selectLeftDown() { + test_rt_39842(true, false); + } + + @Test public void test_rt_39842_selectLeftUp() { + test_rt_39842(true, true); + } + + @Test public void test_rt_39842_selectRightDown() { + test_rt_39842(false, false); + } + + @Test public void test_rt_39842_selectRightUp() { + test_rt_39842(false, true); + } + + private void test_rt_39842(boolean selectToLeft, boolean selectUpwards) { + test_rt_39842_count = 0; + + TreeTableColumn firstNameCol = new TreeTableColumn("First Name"); + firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory("firstName")); + + TreeTableColumn lastNameCol = new TreeTableColumn("Last Name"); + lastNameCol.setCellValueFactory(new TreeItemPropertyValueFactory("lastName")); + + TreeItem root = new TreeItem("root"); + root.getChildren().setAll( + new TreeItem(new Person("Jacob", "Smith", "jacob.smith@example.com")), + new TreeItem(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), + new TreeItem(new Person("Ethan", "Williams", "ethan.williams@example.com")), + new TreeItem(new Person("Emma", "Jones", "emma.jones@example.com")), + new TreeItem(new Person("Michael", "Brown", "michael.brown@example.com"))); + root.setExpanded(true); + + TreeTableView table = new TreeTableView<>(root); + table.setShowRoot(false); + table.getColumns().addAll(firstNameCol, lastNameCol); + + sm = table.getSelectionModel(); + sm.setCellSelectionEnabled(true); + sm.setSelectionMode(SelectionMode.MULTIPLE); + sm.getSelectedCells().addListener((ListChangeListener) c -> test_rt_39842_count++); + + StageLoader sl = new StageLoader(table); + + assertEquals(0, test_rt_39842_count); + + if (selectToLeft) { + if (selectUpwards) { + sm.selectRange(3, lastNameCol, 0, firstNameCol); + } else { + sm.selectRange(0, lastNameCol, 3, firstNameCol); + } + } else { + if (selectUpwards) { + sm.selectRange(3, firstNameCol, 0, lastNameCol); + } else { + sm.selectRange(0, firstNameCol, 3, lastNameCol); + } + } + + // test model state + assertEquals(8, sm.getSelectedCells().size()); + assertEquals(1, test_rt_39842_count); + + // test visual state + for (int row = 0; row <= 3; row++) { + for (int column = 0; column <= 1; column++) { + IndexedCell cell = VirtualFlowTestUtils.getCell(table, row, column); + assertTrue(cell.isSelected()); + } + } + + sl.dispose(); + } }