JDK-8138848 : TableView TableViewArrayListSelectionModel getSelectedIndices() contains -1
  • Type: Bug
  • Component: javafx
  • Sub-Component: controls
  • Affected Version: 8u60
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_8
  • CPU: x86
  • Submitted: 2015-09-30
  • Updated: 2016-01-13
  • Resolved: 2016-01-12
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9Fixed
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.3.9600]

A DESCRIPTION OF THE PROBLEM :
When a range selection is made in an table with a multiple selection model, getSelectedIndices may contain -1 values.
First select a row for instance the third. then expand the selection to a row with an higher row nummer (f.e. the forth), then expand the selection to the first row. 
GetSelectedIndices contains now 0, -1, 2 instead of 0,1,2.

REGRESSION.  Last worked in version 8u51

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
create a table. set table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
add a couple rows (5 or more)

select the second row. (click on the second row)
expand the selection to the third row (hold down shift-key click on the third row)
expand the selection to the first row (hold down shift-key click on the first row)



EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
the selected Indices ( table.getSelectionModel().getSelectedIndices()) should contain 0,1,2
ACTUAL -
the selected Indices contains 0,-1,2

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------


import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class FxTableSelectionTest extends Application {

   final ScrollPane sp = new ScrollPane();
   // @formatter:off 
   private static final ObservableList<Person> data =         
         FXCollections.observableArrayList(
             
             new Person("Astrid", "G��rtner"),
             new Person("Holger", "G��rtner"),
             new Person("Theo", "G��rtner"),
             new Person("Klaus", "G��rtner"),
             new Person("Sigrid", "G��rtner")
             
         );

   // @formatter:on 
   @Override
   public void start(Stage stage) {
      final Label label = new Label("Address Book");
      label.setFont(new Font("Arial", 20));
      Pane main = new VBox();
      TableView table = createTable();
      main.getChildren().addAll(label, table);
      Scene scene = new Scene(main);
      stage.setScene(scene);
      stage.setTitle("Test");

      stage.show();

   }
   @SuppressWarnings({ "rawtypes", "unchecked" })
   public static TableView createTable() {
      final TableView table = new TableView();
      table.setEditable(false);

      TableColumn firstNameCol = new TableColumn("First Name");
      firstNameCol.setCellValueFactory(new PropertyValueFactory<Object, Object>("firstName"));
      firstNameCol.setPrefWidth(200);
      TableColumn lastNameCol = new TableColumn("Last Name");
      lastNameCol.setCellValueFactory(new PropertyValueFactory<>("lastName"));
      lastNameCol.setPrefWidth(200);
      table.setItems(data);
      table.getColumns().addAll(firstNameCol, lastNameCol);

      table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
      table.getSelectionModel().getSelectedIndices().addListener(FxTableSelectionTest::selectionChanged);
      return table;
   }

   private static void selectionChanged(Change<? extends Object> c) {
      while (c.next()) {
         System.out.println("Selection changed: " + c.getList());
      }
   }

   public static void main(String[] args) {
      launch(args);
      setUserAgentStylesheet(STYLESHEET_MODENA);
   }



   public static class Person {

      private final SimpleStringProperty firstName;
      private final SimpleStringProperty lastName;

      private Person(String fName, String lName) {
         this.firstName = new SimpleStringProperty(fName);
         this.lastName = new SimpleStringProperty(lName);
      }

      public String getFirstName() {
         return firstName.get();
      }

      public void setFirstName(String fName) {
         firstName.set(fName);
      }

      public String getLastName() {
         return lastName.get();
      }

      public void setLastName(String fName) {
         lastName.set(fName);
      }

   }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
use this to get the selected indices 

   /**
    * gets the selected indices from the selected Cells, which are the selection model's 
    * 'proper' internal data structure, selectedItems and selectedIndices are both 'read-only and unbacked'.
    * and due to a bug in jdk1.8.0_60 selectedIndices does not work properly in all cases
    * @return the list of indices of the selected rows
    */
   private List<Integer> getSelectedIndices() {
      Set<Integer> selectedRows = new HashSet<Integer>();
      List<TablePosition> selectedCells = m_FxTable.getSelectionModel().getSelectedCells();
      selectedCells.forEach(tablePosition -> {
         selectedRows.add(tablePosition.getRow());
      });
      return new ArrayList<>(selectedRows);
   }



Comments
This has now been resolved due to JDK-8144501. A slight comment - there is a misunderstanding on the expected outcome when shift-clicking. The anchor remains at the initial anchor point, so the selection goes from [1], to [1,2], and then to [0,1]. In other words, it doesn't go to the expected [0,1,2], because the anchor stays at 1.
12-01-2016

Unfortunately I have hit a brick wall on this issue. I am attaching a patch containing my explorations and some unit tests that fail, and I will pick this up again afresh when time permits.
12-11-2015

This is a tough issue to even identify the cause of! If you duplicate the println in the selectionChanged method, you'll see that by the time the second println happens, the output is correct! I'm scratching my head about what exactly is happening - frustratingly debugging doesn't help, as the value 'corrects' itself even when the debugger has paused execution.
11-11-2015