Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8273285

CellEditEvent: event state must be unmodifiable

XMLWordPrintable

      To guarantee that all event handlers/filters see the same event state, it must be effectively unmodifiable. CellEditEvents aren't, failing test:

          @Test
          public void testTableCellEditEventUnmodifiable() {
              TableView<MenuItem> table = createEditableTable();
              TableColumn<MenuItem, String> editingColumn =
                      (TableColumn<MenuItem, String>) table.getColumns().get(0);
              int editingRow = 1;
              String oldValue = table.getItems().get(editingRow).getText();
              String newValue = "edited";
              editingColumn.addEventHandler(TableColumn.<MenuItem, String>editCommitEvent(), e -> {
                  // do commit
                  table.getItems().get(editingRow).setText(newValue);
                  assertEquals(oldValue, e.getOldValue());
              });
              TablePosition<MenuItem, String> editingPosition = new TablePosition<>(table, editingRow, editingColumn);
              CellEditEvent event = new CellEditEvent(table, editingPosition, TableColumn.editCommitEvent(), newValue);
              Event.fireEvent(editingColumn, event);
          }

      Reason is that getOldValue (and also getRowValue) is implemented as a "live" lookup into current table data.

      Fix would be to follow the lead of editEvent in List/Tree-EditEvent and keep references to the state at instantiation of the event

      #########################################################################################################

      Another example:
      The TextField will commit as soon as you lose the focus.
      This works for every possible use case but not if you click on the indentation node while editing the second TreeItem (TreeItem "B").
      This is due the row value is done via a 'live lookup' as described above, which won't work anymore as the row is collapsed via the indentation node.

      // EXAMPLE START

      import javafx.application.Application;
      import javafx.beans.property.SimpleStringProperty;
      import javafx.event.Event;
      import javafx.scene.Scene;
      import javafx.scene.control.TextField;
      import javafx.scene.control.TreeItem;
      import javafx.scene.control.TreeTableCell;
      import javafx.scene.control.TreeTableColumn;
      import javafx.scene.control.TreeTableColumn.CellEditEvent;
      import javafx.scene.control.TreeTablePosition;
      import javafx.scene.control.TreeTableView;
      import javafx.scene.layout.Pane;
      import javafx.stage.Stage;

      public class Test extends Application {

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

          @Override
          public void start(Stage primaryStage) {
              TreeTableView<String> table = new TreeTableView<>();
              TreeTableColumn<String, String> col = new TreeTableColumn<>("HI");
              col.setCellFactory(e -> new TreeTableCell<>() {

                  @Override
                  public void startEdit() {
                      super.startEdit();

                      TextField value = new TextField(getText());
                      value.focusedProperty().addListener((inv, oldV, newV) -> {
                          if (!newV) {
                              TreeTableView<String> table = getTreeTableView();

                              // Inform the TableView of the edit being ready to be committed.
                              final TreeTablePosition<String, String> tablePosition = new TreeTablePosition<>(table,
                                      getTableRow().getIndex(), getTableColumn());
                              CellEditEvent<String, String> cellEditEvent = new CellEditEvent<>(table, tablePosition,
                                      TreeTableColumn.editCommitEvent(), value.getText());
                              Event.fireEvent(getTableColumn(), cellEditEvent);

                              // Update cell.
                              updateItem(value.getText(), false);
                          }
                      });
                      setGraphic(value);
                      value.requestFocus();
                  }

                  @Override
                  public void commitEdit(String newValue) {
                      System.out.println(isEditing());
                      startEdit();
                      super.commitEdit(newValue);
                  }

                  @Override
                  protected void updateItem(String item, boolean empty) {
                      super.updateItem(item, empty);

                      setGraphic(null);
                      if (empty) {
                          setText(null);
                      } else {
                          setText(item);
                      }
                  }
              });
              col.setCellValueFactory(e -> new SimpleStringProperty(e.getValue().getValue()));
              col.setOnEditCommit(e -> {
                  System.out.println("COMMIT");
                  TreeItem<String> rowValue = e.getRowValue();
                  // NPE when 'comitting via indentation node'.
                  rowValue.setValue(e.getNewValue());
              });
              table.getColumns().add(col);
              table.setEditable(true);
              TreeItem<String> item = new TreeItem<>("A");
              item.getChildren().add(new TreeItem<>("B"));

              table.setRoot(item);

              Pane root = new Pane();
              root.getChildren().add(table);
              Scene scene = new Scene(root);
              primaryStage.setScene(scene);
              primaryStage.show();
          }
      }

      // EXAMPLE END

            fastegal Jeanette Winzenburg
            fastegal Jeanette Winzenburg
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: