package demos.gui.uicomponents;
import com.jfoenix.controls.*;
import com.jfoenix.controls.cells.editors.IntegerTextFieldEditorBuilder;
import com.jfoenix.controls.cells.editors.TextFieldEditorBuilder;
import com.jfoenix.controls.cells.editors.base.GenericEditableTreeTableCell;
import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject;
import io.datafx.controller.ViewController;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableColumn.CellEditEvent;
import javax.annotation.PostConstruct;
import java.security.SecureRandom;
import java.util.Random;
import java.util.function.Function;
@ViewController(value = "/fxml/ui/TreeTableView.fxml", title = "Material Design Example")
public class TreeTableViewController {
private static final String PREFIX = "( ";
private static final String POSTFIX = " )";
// readonly table view
@FXML
private JFXTreeTableView<Person> treeTableView;
@FXML
private JFXTreeTableColumn<Person, String> firstNameColumn;
@FXML
private JFXTreeTableColumn<Person, String> lastNameColumn;
@FXML
private JFXTreeTableColumn<Person, Integer> ageColumn;
@FXML
private JFXTextField searchField;
// editable table view
@FXML
private JFXTreeTableView<Person> editableTreeTableView;
@FXML
private JFXTreeTableColumn<Person, String> firstNameEditableColumn;
@FXML
private JFXTreeTableColumn<Person, String> lastNameEditableColumn;
@FXML
private JFXTreeTableColumn<Person, Integer> ageEditableColumn;
@FXML
private Label treeTableViewCount;
@FXML
private JFXButton treeTableViewAdd;
@FXML
private JFXButton treeTableViewRemove;
@FXML
private Label editableTreeTableViewCount;
@FXML
private JFXTextField searchField2;
private final String[] names = {"Morley", "Scott", "Kruger", "Lain",
"Kennedy", "Gawron", "Han", "Hall", "Aydogdu", "Grace",
"Spiers", "Perera", "Smith", "Connoly",
"Sokolowski", "Chaow", "James", "June",};
private final Random random = new SecureRandom();
/**
* init fxml when loaded.
*/
@PostConstruct
public void init() {
setupReadOnlyTableView();
setupEditableTableView();
}
private <T> void setupCellValueFactory(JFXTreeTableColumn<Person, T> column, Function<Person, ObservableValue<T>> mapper) {
column.setCellValueFactory((TreeTableColumn.CellDataFeatures<Person, T> param) -> {
if (column.validateValue(param)) {
return mapper.apply(param.getValue().getValue());
} else {
return column.getComputedValue(param);
}
});
}
private void setupReadOnlyTableView() {
setupCellValueFactory(firstNameColumn, Person::firstNameProperty);
setupCellValueFactory(lastNameColumn, Person::lastNameProperty);
setupCellValueFactory(ageColumn, p -> p.age.asObject());
ObservableList<Person> dummyData = generateDummyData(100);
treeTableView.setRoot(new RecursiveTreeItem<>(dummyData, RecursiveTreeObject::getChildren));
treeTableView.setShowRoot(false);
treeTableViewCount.textProperty()
.bind(Bindings.createStringBinding(() -> PREFIX + treeTableView.getCurrentItemsCount() + POSTFIX,
treeTableView.currentItemsCountProperty()));
treeTableViewAdd.disableProperty()
.bind(Bindings.notEqual(-1, treeTableView.getSelectionModel().selectedIndexProperty()));
treeTableViewRemove.disableProperty()
.bind(Bindings.equal(-1, treeTableView.getSelectionModel().selectedIndexProperty()));
treeTableViewAdd.setOnMouseClicked((e) -> {
dummyData.add(createNewRandomPerson());
final IntegerProperty currCountProp = treeTableView.currentItemsCountProperty();
currCountProp.set(currCountProp.get() + 1);
});
treeTableViewRemove.setOnMouseClicked((e) -> {
dummyData.remove(treeTableView.getSelectionModel().selectedItemProperty().get().getValue());
final IntegerProperty currCountProp = treeTableView.currentItemsCountProperty();
currCountProp.set(currCountProp.get() - 1);
});
searchField.textProperty().addListener(setupSearchField(treeTableView));
}
private void setupEditableTableView() {
setupCellValueFactory(firstNameEditableColumn, Person::firstNameProperty);
setupCellValueFactory(lastNameEditableColumn, Person::lastNameProperty);
setupCellValueFactory(ageEditableColumn, p -> p.age.asObject());
// add editors
firstNameEditableColumn.setCellFactory((TreeTableColumn<Person, String> param) -> {
return new GenericEditableTreeTableCell<>(
new TextFieldEditorBuilder());
});
firstNameEditableColumn.setOnEditCommit((CellEditEvent<Person, String> t) -> {
t.getTreeTableView()
.getTreeItem(t.getTreeTablePosition()
.getRow())
.getValue().firstName.set(t.getNewValue());
});
lastNameEditableColumn.setCellFactory((TreeTableColumn<Person, String> param) -> {
return new GenericEditableTreeTableCell<>(
new TextFieldEditorBuilder());
});
lastNameEditableColumn.setOnEditCommit((CellEditEvent<Person, String> t) -> {
t.getTreeTableView()
.getTreeItem(t.getTreeTablePosition()
.getRow())
.getValue().lastName.set(t.getNewValue());
});
ageEditableColumn.setCellFactory((TreeTableColumn<Person, Integer> param) -> {
return new GenericEditableTreeTableCell<>(
new IntegerTextFieldEditorBuilder());
});
ageEditableColumn.setOnEditCommit((CellEditEvent<Person, Integer> t) -> {
t.getTreeTableView()
.getTreeItem(t.getTreeTablePosition()
.getRow())
.getValue().age.set(t.getNewValue());
});
final ObservableList<Person> dummyData = generateDummyData(200);
editableTreeTableView.setRoot(new RecursiveTreeItem<>(dummyData, RecursiveTreeObject::getChildren));
editableTreeTableView.setShowRoot(false);
editableTreeTableView.setEditable(true);
editableTreeTableViewCount.textProperty()
.bind(Bindings.createStringBinding(() -> PREFIX + editableTreeTableView.getCurrentItemsCount() + POSTFIX,
editableTreeTableView.currentItemsCountProperty()));
searchField2.textProperty()
.addListener(setupSearchField(editableTreeTableView));
}
private ChangeListener<String> setupSearchField(final JFXTreeTableView<TreeTableViewController.Person> tableView) {
return (o, oldVal, newVal) ->
tableView.setPredicate(personProp -> {
final Person person = personProp.getValue();
return person.firstName.get().contains(newVal)
|| person.lastName.get().contains(newVal)
|| Integer.toString(person.age.get()).contains(newVal);
});
}
private ObservableList<Person> generateDummyData(final int numberOfEntries) {
final ObservableList<Person> dummyData = FXCollections.observableArrayList();
for (int i = 0; i < numberOfEntries; i++) {
dummyData.add(createNewRandomPerson());
}
return dummyData;
}
private Person createNewRandomPerson() {
return new Person(names[random.nextInt(names.length)],
names[random.nextInt(names.length)],
random.nextInt(100));
}
/*
* data class
*/
static final class Person extends RecursiveTreeObject<Person> {
final StringProperty firstName;
final StringProperty lastName;
final SimpleIntegerProperty age;
Person(String firstName, String lastName, int age) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
this.age = new SimpleIntegerProperty(age);
}
StringProperty firstNameProperty() {
return firstName;
}
StringProperty lastNameProperty() {
return lastName;
}
}
}