How to enable commit on focusLost for TableView/TreeTableView?

After some digging, turned out that the culprit (aka: the collaborator that cancels the edit before the textField looses focus) is the TableCellBehaviour/Base in its processing of a mousePressed:

  • mousePressed calls simpleSelect(..)
  • on detecting a single click it calls edit(-1, null)
  • which calls the same method on TableView
  • which sets its editingCell property to null
  • a tableCell listens to that property and reacts by canceling its own edit

Unfortunately, a hackaround requires 3 collaborators

  • a TableView with additional api to terminate an edit
  • a TableCellBehaviour with overridden simpleSelect(...) that calls the additional api (instead of edit(-1..)) before calling super
  • a TableCell that is configured with the extended behaviour and is aware of table’s extended properties

Some code snippets (full code) :

// on XTableView:
public void terminateEdit() {
    if (!isEditing()) return;
    // terminatingCell is a property that supporting TableCells can listen to
    setTerminatingCell(getEditingCell());
    if (isEditing()) throw new IllegalStateException(
          "expected editing to be terminated but was " + getEditingCell());
    setTerminatingCell(null);
}

// on XTableCellBehaviour: override simpleSelect
@Override
protected void simpleSelect(MouseEvent e) {
    TableCell<S, T> cell = getControl();
    TableView<S> table = cell.getTableColumn().getTableView();
    if (table instanceof XTableView) {
        ((XTableView<S>) table).terminateEdit();
    }
    super.simpleSelect(e);
}

// on XTextFieldTableCell - this method is called from listener
// to table's terminatingCell property
protected void terminateEdit(TablePosition<S, ?> newPosition) {
    if (!isEditing() || !match(newPosition)) return;
    commitEdit();
}

protected void commitEdit() {
    T edited = getConverter().fromString(myTextField.getText());
    commitEdit(edited);
}

/**
 * Implemented to create XTableCellSkin which supports terminating edits.
 */
@Override
protected Skin<?> createDefaultSkin() {
    return new XTableCellSkin<S, T>(this);
}

Note: the implementation of TableCellBehaviour changed massively between jdk8u5 and jdk8u20 (joys of hacking – not fit for production use 😉 – the method to override in the latter is handleClicks(..)

BTW: massive votingfor JDK-8089514 (was RT-18492 in old jira) might speed up a core fix. Unfortunately, at least the author role is needed to vote/comment bugs in the new tracker.

Leave a Comment