package de.tesis.dynaware.javafx.fancychart;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.util.Callback;
import de.tesis.dynaware.javafx.fancychart.data.DataItem;
import de.tesis.dynaware.javafx.fancychart.data.DataItemDao;
import de.tesis.dynaware.javafx.fancychart.data.DataItemDao.FileFormat;
import de.tesis.dynaware.javafx.fancychart.events.DataItemImportEvent;
import de.tesis.dynaware.javafx.fancychart.events.DataItemSelectionEvent;
public class TabTableController {
private static final int TABLE_MIN_WIDTH = 255;
private static final int TABLE_COL_MIN_WIDTH = 120;
@FXML
StackPane rootPane;
@FXML
TableView<DataItem> tableView;
@FXML
private ImportExportPanelController importExportPanelController;
private int dataSetIndex = 0;
public void initialize() {
assignImportExportButtonActions();
}
public void setDataSetIndex(int index) {
this.dataSetIndex = index;
}
@SuppressWarnings("unchecked")
public void initTable(final ObservableList<DataItem> items) {
final TableColumn<DataItem, Number> xCol = new TableColumn<>("X");
xCol.setCellValueFactory(new PropertyValueFactory<DataItem, Number>("x"));
xCol.setMinWidth(TABLE_COL_MIN_WIDTH);
final TableColumn<DataItem, Number> yCol = new TableColumn<>("Y");
yCol.setCellValueFactory(new PropertyValueFactory<DataItem, Number>("y"));
yCol.setMinWidth(TABLE_COL_MIN_WIDTH);
tableView.setItems(items);
tableView.getColumns().setAll(xCol, yCol);
tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
tableView.setMinWidth(TABLE_MIN_WIDTH);
tableView.setEditable(true);
addSelectionListener();
addCellFactory(xCol, yCol);
}
public void selectDataItem(final int dataItemIndex) {
tableView.getSelectionModel().clearAndSelect(dataItemIndex);
tableView.getFocusModel().focus(dataItemIndex);
tableView.scrollTo(dataItemIndex - 5);
}
public void clearTableSelection() {
tableView.getSelectionModel().clearSelection();
}
private void addSelectionListener() {
tableView.getSelectionModel().getSelectedIndices().addListener(new SelectedTableItemsChangeListener(tableView));
}
private void assignImportExportButtonActions() {
importExportPanelController.getImportButton().setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
importFromFile(dataSetIndex, importExportPanelController.getSelectedFileFormat());
}
});
importExportPanelController.getExportButton().setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
exportToFile(tableView.getItems(), importExportPanelController.getSelectedFileFormat());
}
});
}
private void importFromFile(int index, FileFormat fileFormat) {
FileChooser fileChooser = createFileChooser("Import a " + fileFormat.name() + " file", fileFormat);
File file = fileChooser.showOpenDialog(tableView.getScene().getWindow());
if (file != null) {
List<DataItem> dataItems = DataItemDao.importFromFile(file.getAbsolutePath(), fileFormat);
tableView.fireEvent(new DataItemImportEvent(dataItems, index));
}
}
private void exportToFile(List<DataItem> dataItems, FileFormat fileFormat) {
FileChooser fileChooser = createFileChooser("Export a " + fileFormat + " file", fileFormat);
fileChooser.setInitialFileName("export." + fileFormat.getFileExtension());
File file = fileChooser.showSaveDialog(tableView.getScene().getWindow());
if (file != null) {
DataItemDao.exportToFile(dataItems, file.getAbsolutePath(), fileFormat);
}
}
private static FileChooser createFileChooser(String title, FileFormat fileFormat) {
FileChooser fileChooser = new FileChooser();
fileChooser.setInitialDirectory(File.listRoots()[0]);
fileChooser.setTitle(title);
fileChooser.setSelectedExtensionFilter(new ExtensionFilter(fileFormat.name() + " files", "*."
+ fileFormat.getFileExtension()));
return fileChooser;
}
private void addCellFactory(final TableColumn<DataItem, Number> xCol, final TableColumn<DataItem, Number> yCol) {
final Callback<TableColumn<DataItem, Number>, TableCell<DataItem, Number>> xCellFactory = new Callback<TableColumn<DataItem, Number>, TableCell<DataItem, Number>>() {
@Override
public TableCell<DataItem, Number> call(final TableColumn<DataItem, Number> p) {
return new DoubleEditingCell();
}
};
xCol.setCellFactory(xCellFactory);
final Callback<TableColumn<DataItem, Number>, TableCell<DataItem, Number>> vCellFactory = new Callback<TableColumn<DataItem, Number>, TableCell<DataItem, Number>>() {
@Override
public TableCell<DataItem, Number> call(final TableColumn<DataItem, Number> p) {
return new DoubleEditingCell();
}
};
yCol.setCellFactory(vCellFactory);
}
/**
*
*/
private final class SelectedTableItemsChangeListener implements ListChangeListener<Integer> {
private final TableView<DataItem> tableView;
public SelectedTableItemsChangeListener(final TableView<DataItem> tableView) {
this.tableView = tableView;
}
@Override
public void onChanged(final ListChangeListener.Change<? extends Integer> change) {
final boolean next = change.next();
if (next) {
if (change.wasAdded()) {
final ArrayList<Integer> list = new ArrayList<>(change.getAddedSubList());
tableView.fireEvent(new DataItemSelectionEvent(dataSetIndex, list));
} else if (change.wasRemoved()) {
final ArrayList<Integer> list = new ArrayList<>(change.getRemoved());
tableView.fireEvent(new DataItemSelectionEvent(dataSetIndex, list));
}
}
}
}
/**
*
* @param <T>
*/
private class DoubleEditingCell extends TableCell<DataItem, Number> {
protected TextField textField;
@Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText(getItem().toString());
setGraphic(null);
}
@Override
public void updateItem(final Number item, final boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(getWidth() - getGraphicTextGap() * 2);
final ChangeListener<Boolean> changeListener = new ChangeListener<Boolean>() {
@Override
public void changed(final ObservableValue<? extends Boolean> value, final Boolean oldValue,
final Boolean newValue) {
if (!newValue) {
setValue();
}
}
};
textField.focusedProperty().addListener(changeListener);
textField.addEventHandler(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>() {
@Override
public void handle(final KeyEvent event) {
if (event.getCode().equals(KeyCode.ENTER)) {
setValue();
}
}
});
}
private void setValue() {
try {
final double input = Double.valueOf(textField.getText());
commitEdit(input);
} catch (final NumberFormatException exception) {
System.err.println(exception.getMessage());
cancelEdit();
}
}
private String getString() {
if (getItem() == null) {
return "";
}
return getItem().toString();
}
}
}