package com.kodcu.component;
import javafx.beans.property.ObjectProperty;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.util.StringConverter;
public class CellUtils {
static int TREE_VIEW_HBOX_GRAPHIC_PADDING = 3;
/***************************************************************************
* *
* Private fields *
* *
**************************************************************************/
private final static StringConverter<?> defaultStringConverter = new StringConverter<Object>() {
@Override
public String toString(Object t) {
return t == null ? null : t.toString();
}
@Override
public Object fromString(String string) {
return (Object) string;
}
};
private final static StringConverter<?> defaultTreeItemStringConverter =
new StringConverter<TreeItem<?>>() {
@Override
public String toString(TreeItem<?> treeItem) {
return (treeItem == null || treeItem.getValue() == null) ?
"" : treeItem.getValue().toString();
}
@Override
public TreeItem<?> fromString(String string) {
return new TreeItem<>(string);
}
};
/***************************************************************************
* *
* General convenience *
* *
**************************************************************************/
/*
* Simple method to provide a StringConverter implementation in various cell
* implementations.
*/
@SuppressWarnings("unchecked")
static <T> StringConverter<T> defaultStringConverter() {
return (StringConverter<T>) defaultStringConverter;
}
/*
* Simple method to provide a TreeItem-specific StringConverter
* implementation in various cell implementations.
*/
@SuppressWarnings("unchecked")
static <T> StringConverter<TreeItem<T>> defaultTreeItemStringConverter() {
return (StringConverter<TreeItem<T>>) defaultTreeItemStringConverter;
}
private static <T> String getItemText(Cell<T> cell, StringConverter<T> converter) {
return converter == null ?
cell.getItem() == null ? "" : cell.getItem().toString() :
converter.toString(cell.getItem());
}
static Node getGraphic(TreeItem<?> treeItem) {
return treeItem == null ? null : treeItem.getGraphic();
}
/***************************************************************************
* *
* ChoiceBox convenience *
* *
**************************************************************************/
static <T> void updateItem(final Cell<T> cell,
final StringConverter<T> converter,
final ChoiceBox<T> choiceBox) {
updateItem(cell, converter, null, null, choiceBox);
}
static <T> void updateItem(final Cell<T> cell,
final StringConverter<T> converter,
final HBox hbox,
final Node graphic,
final ChoiceBox<T> choiceBox) {
if (cell.isEmpty()) {
cell.setText(null);
cell.setGraphic(null);
} else {
if (cell.isEditing()) {
if (choiceBox != null) {
choiceBox.getSelectionModel().select(cell.getItem());
}
cell.setText(null);
if (graphic != null) {
hbox.getChildren().setAll(graphic, choiceBox);
cell.setGraphic(hbox);
} else {
cell.setGraphic(choiceBox);
}
} else {
cell.setText(getItemText(cell, converter));
cell.setGraphic(graphic);
}
}
}
;
static <T> ChoiceBox<T> createChoiceBox(
final Cell<T> cell,
final ObservableList<T> items,
final ObjectProperty<StringConverter<T>> converter) {
ChoiceBox<T> choiceBox = new ChoiceBox<T>(items);
choiceBox.setMaxWidth(Double.MAX_VALUE);
choiceBox.converterProperty().bind(converter);
choiceBox.getSelectionModel().selectedItemProperty().addListener((ov, oldValue, newValue) -> {
if (cell.isEditing()) {
cell.commitEdit(newValue);
}
});
return choiceBox;
}
/***************************************************************************
* *
* TextField convenience *
* *
**************************************************************************/
static <T> void updateItem(final Cell<T> cell,
final StringConverter<T> converter,
final TextField textField) {
updateItem(cell, converter, null, null, textField);
}
static <T> void updateItem(final Cell<T> cell,
final StringConverter<T> converter,
final HBox hbox,
final Node graphic,
final TextField textField) {
if (cell.isEmpty()) {
cell.setText(null);
cell.setGraphic(null);
} else {
if (cell.isEditing()) {
if (textField != null) {
textField.setText(getItemText(cell, converter));
}
cell.setText(null);
if (graphic != null) {
hbox.getChildren().setAll(graphic, textField);
cell.setGraphic(hbox);
} else {
cell.setGraphic(textField);
}
} else {
cell.setText(getItemText(cell, converter));
cell.setGraphic(graphic);
}
}
}
static <T> void startEdit(final Cell<T> cell,
final StringConverter<T> converter,
final HBox hbox,
final Node graphic,
final TextField textField) {
if (textField != null) {
textField.setText(getItemText(cell, converter));
}
cell.setText(null);
if (graphic != null) {
hbox.getChildren().setAll(graphic, textField);
cell.setGraphic(hbox);
} else {
cell.setGraphic(textField);
}
textField.selectAll();
// requesting focus so that key input can immediately go into the
// TextField (see RT-28132)
textField.requestFocus();
}
static <T> void cancelEdit(Cell<T> cell, final StringConverter<T> converter, Node graphic) {
cell.setText(getItemText(cell, converter));
cell.setGraphic(graphic);
}
static <T> TextField createTextField(final Cell<T> cell, final StringConverter<T> converter) {
final TextField textField = new TextField(getItemText(cell, converter));
// Use onAction here rather than onKeyReleased (with check for Enter),
// as otherwise we encounter RT-34685
textField.setOnAction(event -> {
if (converter == null) {
throw new IllegalStateException(
"Attempting to convert text input into Object, but provided "
+ "StringConverter is null. Be sure to set a StringConverter "
+ "in your cell factory.");
}
cell.commitEdit(converter.fromString(textField.getText()));
event.consume();
});
textField.setOnMouseExited(event -> {
if (converter == null) {
throw new IllegalStateException(
"Attempting to convert text input into Object, but provided "
+ "StringConverter is null. Be sure to set a StringConverter "
+ "in your cell factory.");
}
cell.commitEdit(converter.fromString(textField.getText()));
event.consume();
});
textField.setOnKeyReleased(t -> {
if (t.getCode() == KeyCode.ESCAPE) {
cell.cancelEdit();
t.consume();
} else if ((t.getCode() == KeyCode.UP) || (t.getCode() == KeyCode.DOWN) || (t.getCode() == KeyCode.LEFT) || (t.getCode() == KeyCode.RIGHT)) {
if (converter == null) {
throw new IllegalStateException(
"Attempting to convert text input into Object, but provided "
+ "StringConverter is null. Be sure to set a StringConverter "
+ "in your cell factory.");
}
cell.commitEdit(converter.fromString(textField.getText()));
t.consume();
}
});
return textField;
}
/***************************************************************************
* *
* ComboBox convenience *
* *
**************************************************************************/
static <T> void updateItem(Cell<T> cell, StringConverter<T> converter, ComboBox<T> comboBox) {
updateItem(cell, converter, null, null, comboBox);
}
static <T> void updateItem(final Cell<T> cell,
final StringConverter<T> converter,
final HBox hbox,
final Node graphic,
final ComboBox<T> comboBox) {
if (cell.isEmpty()) {
cell.setText(null);
cell.setGraphic(null);
} else {
if (cell.isEditing()) {
if (comboBox != null) {
comboBox.getSelectionModel().select(cell.getItem());
}
cell.setText(null);
if (graphic != null) {
hbox.getChildren().setAll(graphic, comboBox);
cell.setGraphic(hbox);
} else {
cell.setGraphic(comboBox);
}
} else {
cell.setText(getItemText(cell, converter));
cell.setGraphic(graphic);
}
}
}
;
static <T> ComboBox<T> createComboBox(final Cell<T> cell,
final ObservableList<T> items,
final ObjectProperty<StringConverter<T>> converter) {
ComboBox<T> comboBox = new ComboBox<T>(items);
comboBox.converterProperty().bind(converter);
comboBox.setMaxWidth(Double.MAX_VALUE);
comboBox.getSelectionModel().selectedItemProperty().addListener((ov, oldValue, newValue) -> {
if (cell.isEditing()) {
cell.commitEdit(newValue);
}
});
return comboBox;
}
}