diff --git a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/CellBehaviorBase.java b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/CellBehaviorBase.java index df74e78eb19..59ff2f123f8 100644 --- a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/CellBehaviorBase.java +++ b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/CellBehaviorBase.java @@ -173,7 +173,7 @@ public void mousePressed(MouseEvent e) { } else { latePress = isSelected(); if (!latePress) { - doSelect(e.getX(), e.getY(), e.getButton(), e.getClickCount(), + doSelect(e, e.getX(), e.getY(), e.getButton(), e.getClickCount(), e.isShiftDown(), e.isShortcutDown()); } } @@ -182,7 +182,7 @@ public void mousePressed(MouseEvent e) { public void mouseReleased(MouseEvent e) { if (latePress) { latePress = false; - doSelect(e.getX(), e.getY(), e.getButton(), e.getClickCount(), + doSelect(e, e.getX(), e.getY(), e.getButton(), e.getClickCount(), e.isShiftDown(), e.isShortcutDown()); } } @@ -199,7 +199,7 @@ public void mouseDragged(MouseEvent e) { * * **************************************************************************/ - protected void doSelect(final double x, final double y, final MouseButton button, + protected void doSelect(MouseEvent e, final double x, final double y, final MouseButton button, final int clickCount, final boolean shiftDown, final boolean shortcutDown) { // we update the cell to point to the new tree node final T cell = getNode(); @@ -243,7 +243,7 @@ protected void doSelect(final double x, final double y, final MouseButton button if (button == MouseButton.PRIMARY || (button == MouseButton.SECONDARY && !selected)) { if (sm.getSelectionMode() == SelectionMode.SINGLE) { - simpleSelect(button, clickCount, shortcutDown); + simpleSelect(e, button, clickCount, shortcutDown); } else { if (shortcutDown) { if (selected) { @@ -263,13 +263,13 @@ protected void doSelect(final double x, final double y, final MouseButton button fm.focus(index); } else { - simpleSelect(button, clickCount, shortcutDown); + simpleSelect(e, button, clickCount, shortcutDown); } } } } - protected void simpleSelect(MouseButton button, int clickCount, boolean shortcutDown) { + protected void simpleSelect(MouseEvent e, MouseButton button, int clickCount, boolean shortcutDown) { final int index = getIndex(); boolean isAlreadySelected; @@ -288,21 +288,38 @@ protected void simpleSelect(MouseButton button, int clickCount, boolean shortcut } } - handleClicks(button, clickCount, isAlreadySelected); + doHandleClick(e, button, clickCount, isAlreadySelected); } - protected void handleClicks(MouseButton button, int clickCount, boolean isAlreadySelected) { + protected void doHandleClick(MouseEvent e, MouseButton button, int clickCount, boolean isAlreadySelected) { + // If not focused yet, we want to shift focus first to the container. + if (!getCellContainer().isFocused()) { + getCellContainer().requestFocus(); + } + + // Consume the event if we handled it, + // so that the event will not bubble up and shift focus back to the container. + if (handleClicks(button, clickCount, isAlreadySelected)) { + e.consume(); + } + } + + protected boolean handleClicks(MouseButton button, int clickCount, boolean isAlreadySelected) { // handle editing, which only occurs with the primary mouse button if (button == MouseButton.PRIMARY) { if (clickCount == 1 && isAlreadySelected) { edit(getNode()); + return true; } else if (clickCount == 1) { - // cancel editing + // stop editing edit(null); + return true; } else if (clickCount == 2 && getNode().isEditable()) { edit(getNode()); + return true; } } + return false; } void selectRows(int focusedIndex, int index) { diff --git a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TableCellBehaviorBase.java b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TableCellBehaviorBase.java index 832a5e6a65f..60bb7aa7a59 100644 --- a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TableCellBehaviorBase.java +++ b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TableCellBehaviorBase.java @@ -33,6 +33,7 @@ import javafx.scene.control.TablePositionBase; import javafx.scene.control.TableSelectionModel; import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; public abstract class TableCellBehaviorBase, C extends IndexedCell> extends CellBehaviorBase { @@ -95,7 +96,7 @@ public TableCellBehaviorBase(C control) { **************************************************************************/ @Override - protected void doSelect(final double x, final double y, final MouseButton button, + protected void doSelect(MouseEvent e, final double x, final double y, final MouseButton button, final int clickCount, final boolean shiftDown, final boolean shortcutDown) { // Note that table.select will reset selection // for out of bounds indexes. So, need to check @@ -146,7 +147,7 @@ protected void doSelect(final double x, final double y, final MouseButton button // what modifiers the user held down as they released the mouse. if (button == MouseButton.PRIMARY || (button == MouseButton.SECONDARY && !selected)) { if (sm.getSelectionMode() == SelectionMode.SINGLE) { - simpleSelect(button, clickCount, shortcutDown); + simpleSelect(e, button, clickCount, shortcutDown); } else { if (shortcutDown) { if (selected) { @@ -195,14 +196,14 @@ protected void doSelect(final double x, final double y, final MouseButton button // return selection back to the focus owner // focus(anchor.getRow(), tableColumn); } else { - simpleSelect(button, clickCount, shortcutDown); + simpleSelect(e, button, clickCount, shortcutDown); } } } } @Override - protected void simpleSelect(MouseButton button, int clickCount, boolean shortcutDown) { + protected void simpleSelect(MouseEvent e, MouseButton button, int clickCount, boolean shortcutDown) { final TableSelectionModel sm = getSelectionModel(); boolean isAlreadySelected; @@ -223,7 +224,7 @@ protected void simpleSelect(MouseButton button, int clickCount, boolean shortcut } } - handleClicks(button, clickCount, isAlreadySelected); + doHandleClick(e, button, clickCount, isAlreadySelected); } private int getColumn() { diff --git a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TableRowBehaviorBase.java b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TableRowBehaviorBase.java index 53dde09eee5..f2521da092d 100644 --- a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TableRowBehaviorBase.java +++ b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TableRowBehaviorBase.java @@ -77,7 +77,7 @@ public TableRowBehaviorBase(T control) { * * **************************************************************************/ - @Override protected void doSelect(final double x, final double y, final MouseButton button, + @Override protected void doSelect(MouseEvent e, final double x, final double y, final MouseButton button, final int clickCount, final boolean shiftDown, final boolean shortcutDown) { final Control table = getCellContainer(); if (table == null) return; @@ -112,11 +112,11 @@ public TableRowBehaviorBase(T control) { final int anchorRow = anchor.getRow(); selectRows(anchorRow, index); } else { - simpleSelect(button, clickCount, shortcutDown); + simpleSelect(e, button, clickCount, shortcutDown); } } } else { - simpleSelect(button, clickCount, shortcutDown); + simpleSelect(e, button, clickCount, shortcutDown); } } diff --git a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeCellBehavior.java b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeCellBehavior.java index 99770ea2c79..da1db315e99 100644 --- a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeCellBehavior.java +++ b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeCellBehavior.java @@ -32,6 +32,7 @@ import javafx.scene.control.TreeItem; import javafx.scene.control.TreeView; import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; public class TreeCellBehavior extends CellBehaviorBase> { @@ -75,23 +76,27 @@ protected void edit(TreeCell cell) { } @Override - protected void handleClicks(MouseButton button, int clickCount, boolean isAlreadySelected) { + protected boolean handleClicks(MouseButton button, int clickCount, boolean isAlreadySelected) { // handle editing, which only occurs with the primary mouse button TreeItem treeItem = getNode().getTreeItem(); if (button == MouseButton.PRIMARY) { if (clickCount == 1 && isAlreadySelected) { edit(getNode()); + return true; } else if (clickCount == 1) { - // cancel editing + // stop editing edit(null); + return true; } else if (clickCount == 2 && treeItem.isLeaf()) { // attempt to edit edit(getNode()); + return true; } else if (clickCount % 2 == 0) { // try to expand/collapse branch tree item treeItem.setExpanded(! treeItem.isExpanded()); } } + return false; } @Override protected boolean handleDisclosureNode(double x, double y) { diff --git a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableCellBehavior.java b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableCellBehavior.java index 235d0d4d16a..953502b118c 100644 --- a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableCellBehavior.java +++ b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableCellBehavior.java @@ -33,6 +33,7 @@ import javafx.scene.control.TreeTableColumn; import javafx.scene.control.TreeTableView; import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; /** */ @@ -140,22 +141,26 @@ public TreeTableCellBehavior(TreeTableCell control) { } @Override - protected void handleClicks(MouseButton button, int clickCount, boolean isAlreadySelected) { + protected boolean handleClicks(MouseButton button, int clickCount, boolean isAlreadySelected) { // handle editing, which only occurs with the primary mouse button TreeItem treeItem = getNode().getTableRow().getTreeItem(); if (button == MouseButton.PRIMARY) { if (clickCount == 1 && isAlreadySelected) { edit(getNode()); + return true; } else if (clickCount == 1) { - // cancel editing + // stop editing edit(null); + return true; } else if (clickCount == 2 && treeItem.isLeaf()) { // attempt to edit edit(getNode()); + return true; } else if (clickCount % 2 == 0) { // try to expand/collapse branch tree item treeItem.setExpanded(! treeItem.isExpanded()); } } + return false; } } diff --git a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableRowBehavior.java b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableRowBehavior.java index 0395e76bbc5..d9cd7bb8881 100644 --- a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableRowBehavior.java +++ b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableRowBehavior.java @@ -33,6 +33,7 @@ import javafx.scene.control.TreeTableRow; import javafx.scene.control.TreeTableView; import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; public class TreeTableRowBehavior extends TableRowBehaviorBase> { @@ -77,22 +78,26 @@ public TreeTableRowBehavior(TreeTableRow control) { } @Override - protected void handleClicks(MouseButton button, int clickCount, boolean isAlreadySelected) { + protected boolean handleClicks(MouseButton button, int clickCount, boolean isAlreadySelected) { // handle editing, which only occurs with the primary mouse button TreeItem treeItem = getNode().getTreeItem(); if (button == MouseButton.PRIMARY) { if (clickCount == 1 && isAlreadySelected) { edit(getNode()); + return true; } else if (clickCount == 1) { - // cancel editing + // stop editing edit(null); + return true; } else if (clickCount == 2 && treeItem.isLeaf()) { // attempt to edit edit(getNode()); + return true; } else if (clickCount % 2 == 0) { // try to expand/collapse branch tree item treeItem.setExpanded(! treeItem.isExpanded()); } } + return false; } } diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/Cell.java b/modules/javafx.controls/src/main/java/javafx/scene/control/Cell.java index efb4b6ffad0..674c89eaf65 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/Cell.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/Cell.java @@ -25,8 +25,6 @@ package javafx.scene.control; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -353,19 +351,17 @@ public Cell() { ((StyleableProperty)focusTraversableProperty()).applyStyle(null, Boolean.FALSE); getStyleClass().addAll(DEFAULT_STYLE_CLASS); - /** - * Indicates whether or not this cell has focus. For example, a + /* + * Indicates whether this cell has focus. For example, a * ListView defines zero or one cell as being the "focused" cell. This cell * would have focused set to true. */ - super.focusedProperty().addListener(new InvalidationListener() { - @Override public void invalidated(Observable property) { - pseudoClassStateChanged(PSEUDO_CLASS_FOCUSED, isFocused()); // TODO is this necessary?? - - // The user has shifted focus, so we should cancel the editing on this cell - if (!isFocused() && isEditing()) { - cancelEdit(); - } + focusedProperty().addListener(_ -> { + pseudoClassStateChanged(PSEUDO_CLASS_FOCUSED, isFocused()); // TODO is this necessary?? + + // The user has shifted focus, so we should stop the editing on this cell. + if (!isFocused() && isEditing()) { + stopEdit(); } }); @@ -373,6 +369,21 @@ public Cell() { pseudoClassStateChanged(PSEUDO_CLASS_EMPTY, true); } + /** + * Stops the edit operation of the cell. + * This method is called when another cell is edited or the focus changed. + *

+ * The default behavior is to cancel the edit. + * This method is meant to be subclassed in case the default behavior is not enough. + * For example, subclasses decide to rather commit the edit operation instead of cancelling. + */ + public void stopEdit() { + if (!isEditing()) { + return; + } + + cancelEdit(); + } /* ************************************************************************* diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/ListCell.java b/modules/javafx.controls/src/main/java/javafx/scene/control/ListCell.java index f7642a691bf..76a4f206393 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/ListCell.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/ListCell.java @@ -592,23 +592,28 @@ private void updateEditing() { if (match && !editing) { startEdit(); } else if (!match && editing) { - // If my index is not the one being edited then I need to cancel - // the edit. The tricky thing here is that as part of this call - // I cannot end up calling list.edit(-1) the way that the standard - // cancelEdit method would do. Yet, I need to call cancelEdit - // so that subclasses which override cancelEdit can execute. So, - // I have to use a kind of hacky flag workaround. - try { - // try-finally to make certain that the flag is reliably reset to true - updateEditingIndex = false; - cancelEdit(); - } finally { - updateEditingIndex = true; - } + doStopEdit(); } } - + /** + * Stops the edit operation. + * If not overwritten, will cancel the edit without changing control'sediting state. + */ + private void doStopEdit() { + // If my index is not the one being edited then I need to cancel + // the edit. The tricky thing here is that as part of this call + // I cannot end up calling list.edit(-1) the way that the standard + // cancelEdit method would do. Yet, I need to call cancelEdit + // so that subclasses which override cancelEdit can execute. So, + // I have to use a kind of hacky flag workaround. + try { + updateEditingIndex = false; + stopEdit(); + } finally { + updateEditingIndex = true; + } + } /* ************************************************************************* * * @@ -654,4 +659,3 @@ public void executeAccessibleAction(AccessibleAction action, Object... parameter } } } - diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/TableCell.java b/modules/javafx.controls/src/main/java/javafx/scene/control/TableCell.java index 870f5a0210e..ce2f52fde4a 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/TableCell.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/TableCell.java @@ -569,29 +569,31 @@ private void updateFocus() { } private void updateEditing() { - if (getIndex() == -1 || getTableView() == null) { - // JDK-8265206: must cancel edit if index changed to -1 by re-use - if (isEditing()) { - doCancelEdit(); + TableView tv = getTableView(); + boolean editing = isEditing(); + if (getIndex() == -1 || tv == null) { + // JDK-8265206: must stop/cancel edit if index changed to -1 by re-use + if (editing) { + doStopEdit(); } return; } - TablePosition editCell = getTableView().getEditingCell(); + TablePosition editCell = tv.getEditingCell(); boolean match = match(editCell); - if (match && ! isEditing()) { + if (match && !editing) { startEdit(); - } else if (! match && isEditing()) { - doCancelEdit(); + } else if (!match && editing) { + doStopEdit(); } } /** - * Switches an editing cell into not editing without changing control's - * editing state. + * Stops the edit operation. + * If not overwritten, will cancel the edit without changing control'sediting state. */ - private void doCancelEdit() { + private void doStopEdit() { // If my index is not the one being edited then I need to cancel // the edit. The tricky thing here is that as part of this call // I cannot end up calling list.edit(-1) the way that the standard @@ -599,9 +601,8 @@ private void doCancelEdit() { // so that subclasses which override cancelEdit can execute. So, // I have to use a kind of hacky flag workaround. try { - // try-finally to make certain that the flag is reliably reset to true updateEditingIndex = false; - cancelEdit(); + stopEdit(); } finally { updateEditingIndex = true; } diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/TableRow.java b/modules/javafx.controls/src/main/java/javafx/scene/control/TableRow.java index 4306dbf54e5..3024d9cd241 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/TableRow.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/TableRow.java @@ -322,10 +322,10 @@ private void updateEditing() { boolean rowMatch = editCell == null ? false : editCell.getRow() == getIndex(); - if (! isEditing() && rowMatch) { + if (!isEditing() && rowMatch) { startEdit(); - } else if (isEditing() && ! rowMatch) { - cancelEdit(); + } else if (isEditing() && !rowMatch) { + stopEdit(); } } diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/TreeCell.java b/modules/javafx.controls/src/main/java/javafx/scene/control/TreeCell.java index 5cbd4ac58aa..334345f2dcd 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/TreeCell.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/TreeCell.java @@ -592,34 +592,37 @@ private void updateEditing() { if (index == -1 || tree == null || treeItem == null) { if (editing) { - // JDK-8265210: must cancel edit if index changed to -1 by re-use - doCancelEditing(); + // JDK-8265210: must stop/cancel edit if index changed to -1 by re-use + doStopEdit(); } return; } final boolean match = treeItem.equals(editItem); - // If my tree item is the item being edited and I'm not currently in + // If my tree item is the item being edited, and I'm not currently in // the edit mode, then I need to enter the edit mode if (match && !editing) { startEdit(); - } else if (! match && editing) { - doCancelEditing(); + } else if (!match && editing) { + doStopEdit(); } } - private void doCancelEditing() { - // If my tree item is not the one being edited then I need to cancel + /** + * Stops the edit operation. + * If not overwritten, will cancel the edit without changing control'sediting state. + */ + private void doStopEdit() { + // If my index is not the one being edited then I need to cancel // the edit. The tricky thing here is that as part of this call - // I cannot end up calling tree.edit(null) the way that the standard + // I cannot end up calling list.edit(-1) the way that the standard // cancelEdit method would do. Yet, I need to call cancelEdit // so that subclasses which override cancelEdit can execute. So, // I have to use a kind of hacky flag workaround. try { - // try-finally to make certain that the flag is reliably reset to true updateEditingIndex = false; - cancelEdit(); + stopEdit(); } finally { updateEditingIndex = true; } diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/TreeTableCell.java b/modules/javafx.controls/src/main/java/javafx/scene/control/TreeTableCell.java index 294f8b10513..732545a7c88 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/TreeTableCell.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/TreeTableCell.java @@ -564,29 +564,30 @@ private void updateFocus() { private void updateEditing() { final TreeTableView tv = getTreeTableView(); + boolean editing = isEditing(); if (getIndex() == -1 || tv == null) { - // JDK-8265206: must cancel edit if index changed to -1 by re-use - if (isEditing()) { - doCancelEdit(); + // JDK-8265206: must stop/cancel edit if index changed to -1 by re-use + if (editing) { + doStopEdit(); } return; } - TreeTablePosition editCell = tv.getEditingCell(); + TreeTablePosition editCell = tv.getEditingCell(); boolean match = match(editCell); - if (match && ! isEditing()) { + if (match && !editing) { startEdit(); - } else if (! match && isEditing()) { - doCancelEdit(); + } else if (!match && editing) { + doStopEdit(); } } /** - * Switches an editing cell into not editing without changing control's - * editing state. + * Stops the edit operation. + * If not overwritten, will cancel the edit without changing control'sediting state. */ - private void doCancelEdit() { + private void doStopEdit() { // If my index is not the one being edited then I need to cancel // the edit. The tricky thing here is that as part of this call // I cannot end up calling list.edit(-1) the way that the standard @@ -594,14 +595,12 @@ private void doCancelEdit() { // so that subclasses which override cancelEdit can execute. So, // I have to use a kind of hacky flag workaround. try { - // try-finally to make certain that the flag is reliably reset to true updateEditingIndex = false; - cancelEdit(); + stopEdit(); } finally { updateEditingIndex = true; } } - private boolean updateEditingIndex = true; private boolean match(TreeTablePosition pos) { diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/TreeTableRow.java b/modules/javafx.controls/src/main/java/javafx/scene/control/TreeTableRow.java index b54ee7d3b8e..3dfe7f8e0ee 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/TreeTableRow.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/TreeTableRow.java @@ -476,10 +476,10 @@ private void updateEditing() { } final TreeItem editItem = editingCell == null ? null : editingCell.getTreeItem(); - if (! isEditing() && getTreeItem().equals(editItem)) { + if (!isEditing() && getTreeItem().equals(editItem)) { startEdit(); - } else if (isEditing() && ! getTreeItem().equals(editItem)) { - cancelEdit(); + } else if (isEditing() && !getTreeItem().equals(editItem)) { + stopEdit(); } } diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/cell/CellUtils.java b/modules/javafx.controls/src/main/java/javafx/scene/control/cell/CellUtils.java index 24723dfe557..56fcac1cd34 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/cell/CellUtils.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/cell/CellUtils.java @@ -242,6 +242,11 @@ static void cancelEdit(Cell cell, final StringConverter converter, Nod static TextField createTextField(final Cell cell, final StringConverter converter) { final TextField textField = new TextField(getItemText(cell, converter)); + textField.focusedProperty().addListener(_ -> { + if (!textField.isFocused() && cell.isEditing()) { + cell.stopEdit(); + } + }); // Use onAction here rather than onKeyReleased (with check for Enter), // as otherwise we encounter JDK-8096726 @@ -255,7 +260,7 @@ static TextField createTextField(final Cell cell, final StringConverter { + textField.setOnKeyPressed(t -> { if (t.getCode() == KeyCode.ESCAPE) { cell.cancelEdit(); t.consume(); @@ -264,6 +269,14 @@ static TextField createTextField(final Cell cell, final StringConverter void stopEdit(Cell cell, StringConverter converter, String text) { + if (converter != null) { + cell.commitEdit(converter.fromString(text)); + } else { + cell.cancelEdit(); + } + } + /* ************************************************************************* diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldListCell.java b/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldListCell.java index 1203bdb301b..45e24e9b3de 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldListCell.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldListCell.java @@ -202,4 +202,14 @@ public final StringConverter getConverter() { super.updateItem(item, empty); CellUtils.updateItem(this, getConverter(), null, null, textField); } + + /** {@inheritDoc} */ + @Override + public void stopEdit() { + if (!isEditing()) { + return; + } + + CellUtils.stopEdit(this, getConverter(), textField.getText()); + } } diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldTableCell.java b/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldTableCell.java index ffdcc3167e9..fa244324bd0 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldTableCell.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldTableCell.java @@ -206,4 +206,14 @@ public final StringConverter getConverter() { super.updateItem(item, empty); CellUtils.updateItem(this, getConverter(), null, null, textField); } + + /** {@inheritDoc} */ + @Override + public void stopEdit() { + if (!isEditing()) { + return; + } + + CellUtils.stopEdit(this, getConverter(), textField.getText()); + } } diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldTreeCell.java b/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldTreeCell.java index 7aa41c6cb8d..3f4515eb4a9 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldTreeCell.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldTreeCell.java @@ -217,6 +217,15 @@ public final StringConverter getConverter() { CellUtils.updateItem(this, getConverter(), hbox, getTreeItemGraphic(), textField); } + /** {@inheritDoc} */ + @Override + public void stopEdit() { + if (!isEditing()) { + return; + } + + CellUtils.stopEdit(this, getConverter(), textField.getText()); + } /* ************************************************************************* diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldTreeTableCell.java b/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldTreeTableCell.java index e27b19b66da..796a7b5165a 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldTreeTableCell.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/cell/TextFieldTreeTableCell.java @@ -208,4 +208,14 @@ public final StringConverter getConverter() { super.updateItem(item, empty); CellUtils.updateItem(this, getConverter(), null, null, textField); } + + /** {@inheritDoc} */ + @Override + public void stopEdit() { + if (!isEditing()) { + return; + } + + CellUtils.stopEdit(this, getConverter(), textField.getText()); + } } diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListCellTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListCellTest.java index f5f78e44a23..64ef29bcc56 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListCellTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListCellTest.java @@ -1185,6 +1185,69 @@ protected boolean isItemChanged(String oldItem, String newItem) { assertTrue(isItemChangedCalled.get()); } + @Test + void testEditStopEditIsCalledAndCancelsEdit() { + AtomicBoolean stopEditCalled = new AtomicBoolean(); + AtomicBoolean cancelEditCalled = new AtomicBoolean(); + + list.setEditable(true); + list.setCellFactory(_ -> new ListCell<>() { + @Override + public void stopEdit() { + super.stopEdit(); + stopEditCalled.set(true); + } + + @Override + public void cancelEdit() { + super.cancelEdit(); + cancelEditCalled.set(true); + } + }); + + stageLoader = new StageLoader(list); + + list.edit(0); + assertFalse(stopEditCalled.get()); + assertFalse(cancelEditCalled.get()); + + list.edit(-1); + assertTrue(stopEditCalled.get()); + assertTrue(cancelEditCalled.get()); + } + + @Test + void testUpdateItemStopEditIsCalledAndCancelsEdit() { + AtomicBoolean stopEditCalled = new AtomicBoolean(); + AtomicBoolean cancelEditCalled = new AtomicBoolean(); + + list.setEditable(true); + list.setCellFactory(_ -> new ListCell<>() { + @Override + public void stopEdit() { + super.stopEdit(); + stopEditCalled.set(true); + } + + @Override + public void cancelEdit() { + super.cancelEdit(); + cancelEditCalled.set(true); + } + }); + + stageLoader = new StageLoader(list); + + list.edit(0); + assertFalse(stopEditCalled.get()); + assertFalse(cancelEditCalled.get()); + + IndexedCell cell = VirtualFlowTestUtils.getCell(list, 0); + cell.updateIndex(-1); + assertTrue(stopEditCalled.get()); + assertTrue(cancelEditCalled.get()); + } + public static class MisbehavingOnCancelListCell extends ListCell { @Override public void cancelEdit() { diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java index 2825762bb6e..ec22d0de212 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java @@ -1308,8 +1308,8 @@ public void updateItem(Counter item, boolean empty) { assertNotNull(listView.getEditingIndex()); listView.getItems().clear(); - assertEquals(1, rt_37853_cancelCount); - assertEquals(0, rt_37853_commitCount); + assertEquals(0, rt_37853_cancelCount); + assertEquals(1, rt_37853_commitCount); sl.dispose(); } diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TableCellTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TableCellTest.java index c148a27de48..61ae2769f41 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TableCellTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TableCellTest.java @@ -978,6 +978,75 @@ protected boolean isItemChanged(String oldItem, String newItem) { assertTrue(isItemChangedCalled.get()); } + @Test + void testEditStopEditIsCalledAndCancelsEdit() { + AtomicBoolean stopEditCalled = new AtomicBoolean(); + AtomicBoolean cancelEditCalled = new AtomicBoolean(); + + TableColumn tableColumn = new TableColumn<>("column"); + table.setEditable(true); + table.getColumns().add(tableColumn); + + tableColumn.setCellFactory(_ -> new TableCell<>() { + @Override + public void stopEdit() { + super.stopEdit(); + stopEditCalled.set(true); + } + + @Override + public void cancelEdit() { + super.cancelEdit(); + cancelEditCalled.set(true); + } + }); + + stageLoader = new StageLoader(table); + + table.edit(0, tableColumn); + assertFalse(stopEditCalled.get()); + assertFalse(cancelEditCalled.get()); + + table.edit(-1, null); + assertTrue(stopEditCalled.get()); + assertTrue(cancelEditCalled.get()); + } + + @Test + void testUpdateItemStopEditIsCalledAndCancelsEdit() { + AtomicBoolean stopEditCalled = new AtomicBoolean(); + AtomicBoolean cancelEditCalled = new AtomicBoolean(); + + TableColumn tableColumn = new TableColumn<>("column"); + table.setEditable(true); + table.getColumns().add(tableColumn); + + tableColumn.setCellFactory(_ -> new TableCell<>() { + @Override + public void stopEdit() { + super.stopEdit(); + stopEditCalled.set(true); + } + + @Override + public void cancelEdit() { + super.cancelEdit(); + cancelEditCalled.set(true); + } + }); + + stageLoader = new StageLoader(table); + + table.edit(0, tableColumn); + assertFalse(stopEditCalled.get()); + assertFalse(cancelEditCalled.get()); + + IndexedCell cell = VirtualFlowTestUtils.getCell(table, 0); + cell.updateIndex(-1); + assertTrue(stopEditCalled.get()); + assertTrue(cancelEditCalled.get()); + } + public static class MisbehavingOnCancelTableCell extends TableCell { @Override diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TableViewTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TableViewTest.java index 31f7badbb0d..501573946f4 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TableViewTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TableViewTest.java @@ -4495,8 +4495,8 @@ private void test_rt38464_selectTests(boolean cellSelection, boolean singleSelec assertNotNull(table.getEditingCell()); table.getItems().clear(); - assertEquals(1, rt_37853_cancelCount); - assertEquals(0, rt_37853_commitCount); + assertEquals(0, rt_37853_cancelCount); + assertEquals(1, rt_37853_commitCount); sl.dispose(); } diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeCellTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeCellTest.java index b257ee789a7..11ada0fe8b7 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeCellTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeCellTest.java @@ -1114,4 +1114,67 @@ protected boolean isItemChanged(String oldItem, String newItem) { assertTrue(isItemChangedCalled.get()); } + + @Test + void testEditStopEditIsCalledAndCancelsEdit() { + AtomicBoolean stopEditCalled = new AtomicBoolean(); + AtomicBoolean cancelEditCalled = new AtomicBoolean(); + + tree.setEditable(true); + tree.setCellFactory(_ -> new TreeCell<>() { + @Override + public void stopEdit() { + super.stopEdit(); + stopEditCalled.set(true); + } + + @Override + public void cancelEdit() { + super.cancelEdit(); + cancelEditCalled.set(true); + } + }); + + stageLoader = new StageLoader(tree); + + tree.edit(tree.getTreeItem(0)); + assertFalse(stopEditCalled.get()); + assertFalse(cancelEditCalled.get()); + + tree.edit(null); + assertTrue(stopEditCalled.get()); + assertTrue(cancelEditCalled.get()); + } + + @Test + void testUpdateItemStopEditIsCalledAndCancelsEdit() { + AtomicBoolean stopEditCalled = new AtomicBoolean(); + AtomicBoolean cancelEditCalled = new AtomicBoolean(); + + tree.setEditable(true); + tree.setCellFactory(_ -> new TreeCell<>() { + @Override + public void stopEdit() { + super.stopEdit(); + stopEditCalled.set(true); + } + + @Override + public void cancelEdit() { + super.cancelEdit(); + cancelEditCalled.set(true); + } + }); + + stageLoader = new StageLoader(tree); + + tree.edit(tree.getTreeItem(0)); + assertFalse(stopEditCalled.get()); + assertFalse(cancelEditCalled.get()); + + IndexedCell cell = VirtualFlowTestUtils.getCell(tree, 0); + cell.updateIndex(-1); + assertTrue(stopEditCalled.get()); + assertTrue(cancelEditCalled.get()); + } } diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableCellTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableCellTest.java index 1a28bf66f77..0ddd609d6d1 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableCellTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableCellTest.java @@ -1290,6 +1290,75 @@ protected boolean isItemChanged(String oldItem, String newItem) { assertTrue(isItemChangedCalled.get()); } + @Test + void testEditStopEditIsCalledAndCancelsEdit() { + AtomicBoolean stopEditCalled = new AtomicBoolean(); + AtomicBoolean cancelEditCalled = new AtomicBoolean(); + + TreeTableColumn tableColumn = new TreeTableColumn<>("column"); + tree.setEditable(true); + tree.getColumns().add(tableColumn); + + tableColumn.setCellFactory(_ -> new TreeTableCell<>() { + @Override + public void stopEdit() { + super.stopEdit(); + stopEditCalled.set(true); + } + + @Override + public void cancelEdit() { + super.cancelEdit(); + cancelEditCalled.set(true); + } + }); + + stageLoader = new StageLoader(tree); + + tree.edit(0, tableColumn); + assertFalse(stopEditCalled.get()); + assertFalse(cancelEditCalled.get()); + + tree.edit(-1, null); + assertTrue(stopEditCalled.get()); + assertTrue(cancelEditCalled.get()); + } + + @Test + void testUpdateItemStopEditIsCalledAndCancelsEdit() { + AtomicBoolean stopEditCalled = new AtomicBoolean(); + AtomicBoolean cancelEditCalled = new AtomicBoolean(); + + TreeTableColumn tableColumn = new TreeTableColumn<>("column"); + tree.setEditable(true); + tree.getColumns().add(tableColumn); + + tableColumn.setCellFactory(_ -> new TreeTableCell<>() { + @Override + public void stopEdit() { + super.stopEdit(); + stopEditCalled.set(true); + } + + @Override + public void cancelEdit() { + super.cancelEdit(); + cancelEditCalled.set(true); + } + }); + + stageLoader = new StageLoader(tree); + + tree.edit(0, tableColumn); + assertFalse(stopEditCalled.get()); + assertFalse(cancelEditCalled.get()); + + IndexedCell cell = VirtualFlowTestUtils.getCell(tree, 0); + cell.updateIndex(-1); + assertTrue(stopEditCalled.get()); + assertTrue(cancelEditCalled.get()); + } + public static class MisbehavingOnCancelTreeTableCell extends TreeTableCell { @Override diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java index aa4703a0e9d..d61d167c97c 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeTableViewTest.java @@ -4823,8 +4823,8 @@ public void test_rt_37853(boolean replaceRoot) { treeTableView.getRoot().getChildren().add(new TreeItem<>("new item " + i)); } } - assertEquals(1, rt_37853_cancelCount); - assertEquals(0, rt_37853_commitCount); + assertEquals(0, rt_37853_cancelCount); + assertEquals(1, rt_37853_commitCount); sl.dispose(); } diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeViewTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeViewTest.java index 802736aa61d..e4501995b9c 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeViewTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/TreeViewTest.java @@ -2368,8 +2368,8 @@ private void test_rt_37853(boolean replaceRoot) { } } - assertEquals(1, rt_37853_cancelCount); - assertEquals(0, rt_37853_commitCount); + assertEquals(0, rt_37853_cancelCount); + assertEquals(1, rt_37853_commitCount); sl.dispose(); } diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/skin/EditAndScrollTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/skin/EditAndScrollTest.java index 9667e8f526f..f2196dd31da 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/skin/EditAndScrollTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/skin/EditAndScrollTest.java @@ -26,6 +26,7 @@ package test.javafx.scene.control.skin; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import static test.com.sun.javafx.scene.control.infrastructure.VirtualizedControlTestUtils.fireMouseOnHorizontalTrack; @@ -96,17 +97,15 @@ public class EditAndScrollTest { @Test public void testTreeTableViewEditingAfterMouseOnVerticalScrollBar() { TreeTableView control = createAndShowTreeTableView(true); - TreeTablePosition editingItem = new TreeTablePosition(control, editingRow, control.getColumns().get(0)); fireMouseOnVerticalTrack(control); - assertEquals(editingItem, control.getEditingCell()); + assertNull(control.getEditingCell()); } @Test public void testTreeTableViewEditingAfterMouseOnHorizontalScrollBar() { TreeTableView control = createAndShowTreeTableView(true); - TreeTablePosition editingItem = new TreeTablePosition(control, editingRow, control.getColumns().get(0)); fireMouseOnHorizontalTrack(control); - assertEquals(editingItem, control.getEditingCell()); + assertNull(control.getEditingCell()); } @Test @@ -173,17 +172,15 @@ private TreeTableColumn createTreeTableColumn() { @Test public void testTableViewEditingAfterMouseOnVerticalScrollBar() { TableView control = createAndShowTableView(true); - TablePosition editingItem = new TablePosition(control, editingRow, control.getColumns().get(0)); fireMouseOnVerticalTrack(control); - assertEquals(editingItem, control.getEditingCell()); + assertNull(control.getEditingCell()); } @Test public void testTableViewEditingAfterMouseOnHorizontalScrollBar() { TableView control = createAndShowTableView(true); - TablePosition editingItem = new TablePosition(control, editingRow, control.getColumns().get(0)); fireMouseOnHorizontalTrack(control); - assertEquals(editingItem, control.getEditingCell()); + assertNull(control.getEditingCell()); } @Test @@ -247,17 +244,15 @@ private TableColumn createColumn() { @Test public void testTreeViewEditingAfterMouseOnVerticalScrollBar() { TreeView control = createAndShowTreeView(true); - TreeItem editingItem = control.getTreeItem(editingRow); fireMouseOnVerticalTrack(control); - assertEquals(editingItem, control.getEditingItem()); + assertNull(control.getEditingItem()); } @Test public void testTreeViewEditingAfterMouseOnHorizontalScrollBar() { TreeView control = createAndShowTreeView(true); - TreeItem editingItem = control.getTreeItem(editingRow); fireMouseOnHorizontalTrack(control); - assertEquals(editingItem, control.getEditingItem()); + assertNull(control.getEditingItem()); } @Test @@ -315,14 +310,14 @@ private TreeView createAndShowTreeView(boolean startEdit) { public void testListViewEditingAfterMouseOnVerticalScrollBar() { ListView control = createAndShowListView(true); fireMouseOnVerticalTrack(control); - assertEquals(editingRow, control.getEditingIndex()); + assertEquals(-1, control.getEditingIndex()); } @Test public void testListViewEditingAfterMouseOnHorizontalScrollBar() { ListView control = createAndShowListView(true); fireMouseOnHorizontalTrack(control); - assertEquals(editingRow, control.getEditingIndex()); + assertEquals(-1, control.getEditingIndex()); } @Test @@ -384,7 +379,7 @@ private void assertFocusedAfterMouseOnScrollBar(Control control, Orientation dir Button focusableControl = new Button("dummy"); showControl(focusableControl, true); if (dir == Orientation.HORIZONTAL) { - fireMouseOnHorizontalTrack(control); + fireMouseOnHorizontalTrack(control); } else { fireMouseOnVerticalTrack(control); }