add and remove rows

This commit is contained in:
Andreas Billmann
2016-01-13 23:07:29 +01:00
parent 4e94cf2091
commit 16b848adc9
5 changed files with 174 additions and 62 deletions

View File

@@ -27,7 +27,9 @@
package ninja.javafx.smartcsv.fx; package ninja.javafx.smartcsv.fx;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.event.EventHandler; import javafx.event.EventHandler;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@@ -68,6 +70,7 @@ import java.util.ResourceBundle;
import static java.lang.Math.max; import static java.lang.Math.max;
import static javafx.application.Platform.exit; import static javafx.application.Platform.exit;
import static javafx.application.Platform.runLater; import static javafx.application.Platform.runLater;
import static javafx.beans.binding.Bindings.*;
import static javafx.scene.layout.AnchorPane.*; import static javafx.scene.layout.AnchorPane.*;
/** /**
@@ -141,12 +144,23 @@ public class SmartCSVController extends FXMLController {
@FXML @FXML
private MenuItem saveAsMenuItem; private MenuItem saveAsMenuItem;
@FXML
private MenuItem deleteRowMenuItem;
@FXML
private MenuItem addRowMenuItem;
@FXML @FXML
private Button saveButton; private Button saveButton;
@FXML @FXML
private Button saveAsButton; private Button saveAsButton;
@FXML
private Button deleteRowButton;
@FXML
private Button addRowButton;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// members // members
@@ -158,8 +172,8 @@ public class SmartCSVController extends FXMLController {
private TableView<CSVRow> tableView; private TableView<CSVRow> tableView;
private BooleanProperty fileChanged = new SimpleBooleanProperty(true); private BooleanProperty fileChanged = new SimpleBooleanProperty(true);
private ResourceBundle resourceBundle; private ResourceBundle resourceBundle;
private File currentCsvFile; private ObjectProperty<File> currentCsvFile = new SimpleObjectProperty<>();
private File currentConfigFile; private ObjectProperty<File> currentConfigFile= new SimpleObjectProperty<>();
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -169,16 +183,30 @@ public class SmartCSVController extends FXMLController {
@Override @Override
public void initialize(URL location, ResourceBundle resourceBundle) { public void initialize(URL location, ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle; this.resourceBundle = resourceBundle;
saveFileService.setWriter(csvFileWriter);
cellFactory = new ValidationCellFactory(resourceBundle); setupTableCellFactory();
errorList.setCellFactory(param -> new ValidationErrorListCell(resourceBundle)); setupErrorListCellFactory();
errorList.getSelectionModel().selectedItemProperty().addListener(observable -> scrollToError()); setupErrorListSelectionListener();
fileChanged.addListener(observable -> setStateName());
setStateName(); bindMenuItemsToCsvFileExtistence(saveMenuItem, saveAsMenuItem, addRowMenuItem);
loadCsvPreferences(); bindButtonsToCsvFileExistence(saveButton, saveAsButton, addRowButton);
bindCsvFileName();
bindConfigFileName();
loadCsvPreferencesFromFile();
} }
private void setupErrorListSelectionListener() {
errorList.getSelectionModel().selectedItemProperty().addListener(observable -> scrollToError());
}
private void setupErrorListCellFactory() {
errorList.setCellFactory(param -> new ValidationErrorListCell(resourceBundle));
}
private void setupTableCellFactory() {
cellFactory = new ValidationCellFactory(resourceBundle);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -198,39 +226,41 @@ public class SmartCSVController extends FXMLController {
@FXML @FXML
public void openCsv(ActionEvent actionEvent) { public void openCsv(ActionEvent actionEvent) {
currentCsvFile = loadFile(csvLoader, currentCsvFile.setValue(
loadFile(
csvLoader,
"CSV files (*.csv)", "CSV files (*.csv)",
"*.csv", "*.csv",
"Open CSV", "Open CSV",
currentCsvFile); currentCsvFile.getValue()));
enableSaveMenuItems();
setCsvFileName();
} }
@FXML @FXML
public void openConfig(ActionEvent actionEvent) { public void openConfig(ActionEvent actionEvent) {
currentConfigFile = loadFile(validationLoader, currentConfigFile.setValue(
loadFile(
validationLoader,
"JSON files (*.json)", "JSON files (*.json)",
"*.json", "*.json",
"Open Validation Configuration", "Open Validation Configuration",
currentConfigFile); currentConfigFile.getValue()));
setConfigFileName();
} }
@FXML @FXML
public void saveCsv(ActionEvent actionEvent) { public void saveCsv(ActionEvent actionEvent) {
csvFileWriter.setModel(model); csvFileWriter.setModel(model);
useSaveFileService(csvFileWriter, currentCsvFile); useSaveFileService(csvFileWriter, currentCsvFile.getValue());
} }
@FXML @FXML
public void saveAsCsv(ActionEvent actionEvent) { public void saveAsCsv(ActionEvent actionEvent) {
csvFileWriter.setModel(model); csvFileWriter.setModel(model);
currentCsvFile = saveFile(csvFileWriter, currentCsvFile.setValue(
saveFile(
csvFileWriter,
"CSV files (*.csv)", "CSV files (*.csv)",
"*.csv", "*.csv",
currentCsvFile); currentCsvFile.getValue()));
setCsvFileName();
} }
@FXML @FXML
@@ -271,6 +301,25 @@ public class SmartCSVController extends FXMLController {
} }
} }
@FXML
public void deleteRow(ActionEvent actionEvent) {
model.getRows().removeAll(tableView.getSelectionModel().getSelectedItems());
fileChanged.setValue(true);
resetContent();
}
@FXML
public void addRow(ActionEvent actionEvent) {
CSVRow row = model.addRow();
for (String column : model.getHeader()) {
row.addValue(column, "");
}
fileChanged.setValue(true);
resetContent();
selectNewRow();
}
public boolean canExit() { public boolean canExit() {
boolean canExit = true; boolean canExit = true;
if (model != null && fileChanged.get()) { if (model != null && fileChanged.get()) {
@@ -292,32 +341,46 @@ public class SmartCSVController extends FXMLController {
// private methods // private methods
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void enableSaveMenuItems() { private void selectNewRow() {
if (currentCsvFile != null) { int lastRow = tableView.getItems().size()-1;
saveMenuItem.setDisable(false); tableView.scrollTo(lastRow);
saveAsMenuItem.setDisable(false); tableView.requestFocus();
saveButton.setDisable(false); tableView.getSelectionModel().select(lastRow);
saveAsButton.setDisable(false); }
private void bindMenuItemsToCsvFileExtistence(MenuItem... items) {
for (MenuItem item: items) {
item.disableProperty().bind(isNull(currentCsvFile));
} }
} }
private void setCsvFileName() { private void bindButtonsToCsvFileExistence(Button... items) {
if (currentCsvFile != null) { for (Button item: items) {
csvName.setText(currentCsvFile.getName()); item.disableProperty().bind(isNull(currentCsvFile));
} else {
csvName.setText("");
} }
} }
private void setConfigFileName() { private void bindMenuItemsToTableSelection(MenuItem... items) {
if (currentConfigFile != null) { for (MenuItem item: items) {
configurationName.setText(currentConfigFile.getName()); item.disableProperty().bind(lessThan(tableView.getSelectionModel().selectedIndexProperty(), 0));
} else {
configurationName.setText("");
} }
} }
private void loadCsvPreferences() { private void bindButtonsToTableSelection(Button... items) {
for (Button item: items) {
item.disableProperty().bind(lessThan(tableView.getSelectionModel().selectedIndexProperty(), 0));
}
}
private void bindCsvFileName() {
csvName.textProperty().bind(selectString(currentCsvFile, "name"));
}
private void bindConfigFileName() {
configurationName.textProperty().bind(selectString(currentConfigFile, "name"));
}
private void loadCsvPreferencesFromFile() {
if (PREFERENCES_FILE.exists()) { if (PREFERENCES_FILE.exists()) {
useLoadFileService(preferencesLoader, PREFERENCES_FILE); useLoadFileService(preferencesLoader, PREFERENCES_FILE);
} }
@@ -432,9 +495,13 @@ public class SmartCSVController extends FXMLController {
model.setValidator(validationLoader.getValidator()); model.setValidator(validationLoader.getValidator());
tableView = new TableView<>(); tableView = new TableView<>();
bindMenuItemsToTableSelection(deleteRowMenuItem);
bindButtonsToTableSelection(deleteRowButton);
for (String column : model.getHeader()) { for (String column : model.getHeader()) {
addColumn(column, tableView); addColumn(column, tableView);
} }
tableView.getItems().setAll(model.getRows()); tableView.getItems().setAll(model.getRows());
tableView.setEditable(true); tableView.setEditable(true);
@@ -484,16 +551,4 @@ public class SmartCSVController extends FXMLController {
} }
} }
} }
private void setStateName() {
if (model != null) {
if (fileChanged.get()) {
stateName.setText(resourceBundle.getString("state.changed"));
} else {
stateName.setText(resourceBundle.getString("state.unchanged"));
}
} else {
stateName.setText("");
}
}
} }

View File

@@ -49,6 +49,16 @@
-glyph-size: 14px; -glyph-size: 14px;
} }
.delete-icon {
-glyph-name: "MINUS";
-glyph-size: 14px;
}
.add-icon {
-glyph-name: "PLUS";
-glyph-size: 14px;
}
/* toolbar customization based on http://fxexperience.com/2012/02/customized-segmented-toolbar-buttons/ */ /* toolbar customization based on http://fxexperience.com/2012/02/customized-segmented-toolbar-buttons/ */
#background { #background {
@@ -96,6 +106,16 @@
-fx-fill: white; -fx-fill: white;
} }
.tool-bar .delete-icon {
-glyph-size: 16px;
-fx-fill: white;
}
.tool-bar .add-icon {
-glyph-size: 16px;
-fx-fill: white;
}
.segmented-button-bar .button { .segmented-button-bar .button {
-fx-background-color: -fx-background-color:
-darkest-black, -darkest-black,

View File

@@ -52,6 +52,20 @@
</MenuItem> </MenuItem>
</items> </items>
</Menu> </Menu>
<Menu mnemonicParsing="false" text="%menu.edit">
<items>
<MenuItem fx:id="deleteRowMenuItem" disable="true" mnemonicParsing="false" onAction="#deleteRow" text="%menu.delete.row">
<graphic>
<FontAwesomeIconView styleClass="delete-icon" />
</graphic>
</MenuItem>
<MenuItem fx:id="addRowMenuItem" disable="true" mnemonicParsing="false" onAction="#addRow" text="%menu.add.row">
<graphic>
<FontAwesomeIconView styleClass="add-icon" />
</graphic>
</MenuItem>
</items>
</Menu>
<Menu mnemonicParsing="false" text="%menu.help"> <Menu mnemonicParsing="false" text="%menu.help">
<items> <items>
<MenuItem mnemonicParsing="false" onAction="#about" text="%menu.about"> <MenuItem mnemonicParsing="false" onAction="#about" text="%menu.about">
@@ -97,6 +111,25 @@
<FontAwesomeIconView styleClass="save-icon" /> <FontAwesomeIconView styleClass="save-icon" />
</graphic> </graphic>
</Button> </Button>
</HBox>
<Region styleClass="spacer" />
<HBox styleClass="segmented-button-bar">
<Button fx:id="deleteRowButton" disable="true" mnemonicParsing="false" onAction="#deleteRow" styleClass="first">
<tooltip>
<Tooltip text="%menu.delete.row" />
</tooltip>
<graphic>
<FontAwesomeIconView styleClass="delete-icon" />
</graphic>
</Button>
<Button fx:id="addRowButton" disable="true" mnemonicParsing="false" onAction="#addRow" styleClass="last">
<tooltip>
<Tooltip text="%menu.add.row" />
</tooltip>
<graphic>
<FontAwesomeIconView styleClass="add-icon" />
</graphic>
</Button>
</HBox> </HBox>
<Region styleClass="spacer" /> <Region styleClass="spacer" />
<HBox styleClass="segmented-button-bar"> <HBox styleClass="segmented-button-bar">
@@ -170,11 +203,9 @@
<FontAwesomeIconView styleClass="open-icon" GridPane.hgrow="NEVER" /> <FontAwesomeIconView styleClass="open-icon" GridPane.hgrow="NEVER" />
<Label text="%stateline.csv" GridPane.columnIndex="1" GridPane.hgrow="NEVER" /> <Label text="%stateline.csv" GridPane.columnIndex="1" GridPane.hgrow="NEVER" />
<Label fx:id="csvName" GridPane.columnIndex="2" GridPane.hgrow="ALWAYS" /> <Label fx:id="csvName" GridPane.columnIndex="2" GridPane.hgrow="ALWAYS" />
<Label text="%stateline.state" GridPane.columnIndex="3" GridPane.hgrow="NEVER" /> <FontAwesomeIconView styleClass="open-icon" GridPane.columnIndex="3" GridPane.hgrow="NEVER" />
<Label fx:id="stateName" GridPane.columnIndex="4" GridPane.hgrow="ALWAYS" /> <Label text="%stateline.configuration" GridPane.columnIndex="4" GridPane.hgrow="NEVER" />
<FontAwesomeIconView styleClass="open-icon" GridPane.columnIndex="5" GridPane.hgrow="NEVER" /> <Label fx:id="configurationName" GridPane.columnIndex="5" GridPane.hgrow="ALWAYS" />
<Label text="%stateline.configuration" GridPane.columnIndex="6" GridPane.hgrow="NEVER" />
<Label fx:id="configurationName" GridPane.columnIndex="7" GridPane.hgrow="ALWAYS" />
</children> </children>
<BorderPane.margin> <BorderPane.margin>
<Insets bottom="4.0" left="8.0" right="8.0" top="4.0" /> <Insets bottom="4.0" left="8.0" right="8.0" top="4.0" />

View File

@@ -8,6 +8,9 @@ menu.file = File
menu.edit = Edit menu.edit = Edit
menu.help = Help menu.help = Help
menu.preferences = Preferences menu.preferences = Preferences
menu.delete.row = Delete row
menu.add.row = Add row
title.validation.errors = Validation Errors: title.validation.errors = Validation Errors:
stateline.csv = CSV: stateline.csv = CSV:

View File

@@ -16,6 +16,9 @@ menu.file = Datei
menu.edit = Bearbeiten menu.edit = Bearbeiten
menu.help = Hilfe menu.help = Hilfe
menu.preferences = Einstellungen menu.preferences = Einstellungen
menu.delete.row = Zeile l\u00f6schen
menu.add.row = Zeile hinzuf\u00fcgen
title.validation.errors = Fehler in der Datei: title.validation.errors = Fehler in der Datei:
stateline.csv = CSV: stateline.csv = CSV: