mirror of
https://github.com/frosch95/SmartCSV.fx.git
synced 2026-04-11 13:38:23 +02:00
show state and allow exit based on state
This commit is contained in:
@@ -27,9 +27,12 @@
|
|||||||
package ninja.javafx.smartcsv.fx;
|
package ninja.javafx.smartcsv.fx;
|
||||||
|
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.event.EventHandler;
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
import javafx.stage.WindowEvent;
|
||||||
import org.springframework.context.annotation.*;
|
import org.springframework.context.annotation.*;
|
||||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||||
|
|
||||||
@@ -46,6 +49,8 @@ public class SmartCSV extends Application {
|
|||||||
String name = appContext.getEnvironment().getProperty("application.name");
|
String name = appContext.getEnvironment().getProperty("application.name");
|
||||||
String version = appContext.getEnvironment().getProperty("application.version");
|
String version = appContext.getEnvironment().getProperty("application.version");
|
||||||
|
|
||||||
|
Platform.setImplicitExit(false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
showUI(primaryStage, name, version);
|
showUI(primaryStage, name, version);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -80,6 +85,12 @@ public class SmartCSV extends Application {
|
|||||||
primaryStage.setTitle(String.format("%s %s", name, version));
|
primaryStage.setTitle(String.format("%s %s", name, version));
|
||||||
primaryStage.show();
|
primaryStage.show();
|
||||||
primaryStage.setMaximized(true);
|
primaryStage.setMaximized(true);
|
||||||
|
|
||||||
|
primaryStage.setOnCloseRequest(event -> {
|
||||||
|
if (!smartCVSController.canExit()) {
|
||||||
|
event.consume();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,12 @@
|
|||||||
package ninja.javafx.smartcsv.fx;
|
package ninja.javafx.smartcsv.fx;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.InvalidationListener;
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.concurrent.Service;
|
import javafx.concurrent.Service;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
@@ -53,6 +59,7 @@ import org.springframework.stereotype.Component;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
import static java.lang.Math.max;
|
import static java.lang.Math.max;
|
||||||
@@ -81,7 +88,13 @@ public class SmartCSVController extends FXMLController {
|
|||||||
private BorderPane applicationPane;
|
private BorderPane applicationPane;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label stateline;
|
private Label csvName;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label configurationName;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label stateName;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ListView errorList;
|
private ListView errorList;
|
||||||
@@ -100,6 +113,8 @@ public class SmartCSVController extends FXMLController {
|
|||||||
private CSVModel model;
|
private CSVModel model;
|
||||||
private TableView<CSVRow> tableView;
|
private TableView<CSVRow> tableView;
|
||||||
private File lastDirectory;
|
private File lastDirectory;
|
||||||
|
private BooleanProperty fileChanged = new SimpleBooleanProperty(true);
|
||||||
|
private ResourceBundle resourceBundle;
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -108,12 +123,13 @@ public class SmartCSVController extends FXMLController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL location, ResourceBundle resourceBundle) {
|
public void initialize(URL location, ResourceBundle resourceBundle) {
|
||||||
|
this.resourceBundle = resourceBundle;
|
||||||
|
saveCSVService.setWriter(csvFileWriter);
|
||||||
cellFactory = new ValidationCellFactory(resourceBundle);
|
cellFactory = new ValidationCellFactory(resourceBundle);
|
||||||
stateline.setVisible(false);
|
|
||||||
errorList.setCellFactory(param -> new ValidationErrorListCell(resourceBundle));
|
errorList.setCellFactory(param -> new ValidationErrorListCell(resourceBundle));
|
||||||
errorList.getSelectionModel().selectedItemProperty().addListener(
|
errorList.getSelectionModel().selectedItemProperty().addListener(observable -> scrollToError());
|
||||||
observable -> scrollToError()
|
fileChanged.addListener(observable -> setStateName());
|
||||||
);
|
setStateName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -134,12 +150,12 @@ public class SmartCSVController extends FXMLController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void openCsv(ActionEvent actionEvent) {
|
public void openCsv(ActionEvent actionEvent) {
|
||||||
loadFile(csvLoader, "CSV files (*.csv)", "*.csv", "Open CSV");
|
loadFile(csvLoader, "CSV files (*.csv)", "*.csv", "Open CSV", csvName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void openConfig(ActionEvent actionEvent) {
|
public void openConfig(ActionEvent actionEvent) {
|
||||||
loadFile(validationLoader, "JSON files (*.json)", "*.json", "Open Validation Configuration");
|
loadFile(validationLoader, "JSON files (*.json)", "*.json", "Open Validation Configuration", configurationName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@@ -154,8 +170,10 @@ public class SmartCSVController extends FXMLController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void close(ActionEvent actionEvent) {
|
public void close(ActionEvent actionEvent) {
|
||||||
|
if (canExit()) {
|
||||||
Platform.exit();
|
Platform.exit();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void about(ActionEvent actionEvent) {
|
public void about(ActionEvent actionEvent) {
|
||||||
@@ -176,13 +194,30 @@ public class SmartCSVController extends FXMLController {
|
|||||||
|
|
||||||
|
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canExit() {
|
||||||
|
boolean canExit = true;
|
||||||
|
if (model != null && fileChanged.get()) {
|
||||||
|
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||||
|
alert.setTitle(resourceBundle.getString("dialog.exit.title"));
|
||||||
|
alert.setHeaderText(resourceBundle.getString("dialog.exit.header.text"));
|
||||||
|
alert.setContentText(resourceBundle.getString("dialog.exit.text"));
|
||||||
|
|
||||||
|
Optional<ButtonType> result = alert.showAndWait();
|
||||||
|
if (result.get() != ButtonType.OK){
|
||||||
|
canExit = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return canExit;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// private methods
|
// private methods
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void loadFile(FileReader fileReader, String filterText, String filter, String title) {
|
private void loadFile(FileReader fileReader, String filterText, String filter, String title, Label fileLabel) {
|
||||||
final FileChooser fileChooser = new FileChooser();
|
final FileChooser fileChooser = new FileChooser();
|
||||||
|
|
||||||
//Set extension filter
|
//Set extension filter
|
||||||
@@ -197,6 +232,7 @@ public class SmartCSVController extends FXMLController {
|
|||||||
//Show open file dialog
|
//Show open file dialog
|
||||||
final File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow());
|
final File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow());
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
|
loadCSVService.setFileLabel(fileLabel);
|
||||||
loadCSVService.setFile(file);
|
loadCSVService.setFile(file);
|
||||||
loadCSVService.setFileReader(fileReader);
|
loadCSVService.setFileReader(fileReader);
|
||||||
loadCSVService.restart();
|
loadCSVService.restart();
|
||||||
@@ -220,6 +256,7 @@ public class SmartCSVController extends FXMLController {
|
|||||||
final File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow());
|
final File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow());
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
model.setFilepath(file.getAbsolutePath());
|
model.setFilepath(file.getAbsolutePath());
|
||||||
|
saveCSVService.setWriter(writer);
|
||||||
saveCSVService.restart();
|
saveCSVService.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,7 +302,10 @@ public class SmartCSVController extends FXMLController {
|
|||||||
public void handle(TableColumn.CellEditEvent<CSVRow, CSVValue> event) {
|
public void handle(TableColumn.CellEditEvent<CSVRow, CSVValue> event) {
|
||||||
event.getTableView().getItems().get(event.getTablePosition().getRow()).
|
event.getTableView().getItems().get(event.getTablePosition().getRow()).
|
||||||
getColumns().get(header).setValue(event.getNewValue());
|
getColumns().get(header).setValue(event.getNewValue());
|
||||||
runLater(() -> model.revalidate());
|
runLater(() -> {
|
||||||
|
fileChanged.setValue(true);
|
||||||
|
model.revalidate();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -284,6 +324,19 @@ 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("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// inner class
|
// inner class
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -295,6 +348,7 @@ public class SmartCSVController extends FXMLController {
|
|||||||
|
|
||||||
private File file = null;
|
private File file = null;
|
||||||
private FileReader fileReader;
|
private FileReader fileReader;
|
||||||
|
private Label fileLabel;
|
||||||
|
|
||||||
public void setFile(File value) {
|
public void setFile(File value) {
|
||||||
file = value;
|
file = value;
|
||||||
@@ -302,6 +356,9 @@ public class SmartCSVController extends FXMLController {
|
|||||||
public void setFileReader(FileReader fileReader) {
|
public void setFileReader(FileReader fileReader) {
|
||||||
this.fileReader = fileReader;
|
this.fileReader = fileReader;
|
||||||
}
|
}
|
||||||
|
public void setFileLabel(Label fileLabel) {
|
||||||
|
this.fileLabel = fileLabel;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Task createTask() {
|
protected Task createTask() {
|
||||||
@@ -312,7 +369,11 @@ public class SmartCSVController extends FXMLController {
|
|||||||
try {
|
try {
|
||||||
lastDirectory = file.getParentFile();
|
lastDirectory = file.getParentFile();
|
||||||
fileReader.read(file);
|
fileReader.read(file);
|
||||||
runLater(SmartCSVController.this::resetContent);
|
runLater(() -> {
|
||||||
|
fileLabel.setText(file.getName());
|
||||||
|
resetContent();
|
||||||
|
fileChanged.setValue(false);
|
||||||
|
});
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -321,6 +382,7 @@ public class SmartCSVController extends FXMLController {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -328,14 +390,23 @@ public class SmartCSVController extends FXMLController {
|
|||||||
*/
|
*/
|
||||||
private class SaveCSVService extends Service {
|
private class SaveCSVService extends Service {
|
||||||
|
|
||||||
|
private CSVFileWriter writer;
|
||||||
|
|
||||||
|
public void setWriter(CSVFileWriter writer) {
|
||||||
|
this.writer = writer;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Task createTask() {
|
protected Task createTask() {
|
||||||
return new Task() {
|
return new Task() {
|
||||||
@Override
|
@Override
|
||||||
protected Void call() throws Exception {
|
protected Void call() throws Exception {
|
||||||
try {
|
try {
|
||||||
csvFileWriter.saveFile(model);
|
writer.saveFile(model);
|
||||||
runLater(SmartCSVController.this::resetContent);
|
runLater(() -> {
|
||||||
|
resetContent();
|
||||||
|
fileChanged.setValue(false);
|
||||||
|
});
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -343,5 +414,6 @@ public class SmartCSVController extends FXMLController {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.net.*?>
|
||||||
<?import javafx.geometry.*?>
|
<?import javafx.geometry.*?>
|
||||||
<?import javafx.scene.control.*?>
|
<?import javafx.scene.control.*?>
|
||||||
<?import java.lang.*?>
|
<?import java.lang.*?>
|
||||||
@@ -55,19 +56,35 @@
|
|||||||
</items>
|
</items>
|
||||||
</SplitPane>
|
</SplitPane>
|
||||||
</center>
|
</center>
|
||||||
<bottom>
|
|
||||||
<HBox spacing="8.0" BorderPane.alignment="CENTER">
|
|
||||||
<children>
|
|
||||||
<Label fx:id="stateline" text="Status" HBox.hgrow="ALWAYS" />
|
|
||||||
</children>
|
|
||||||
<BorderPane.margin>
|
|
||||||
<Insets bottom="4.0" left="4.0" right="4.0" top="4.0" />
|
|
||||||
</BorderPane.margin>
|
|
||||||
</HBox>
|
|
||||||
</bottom>
|
|
||||||
<left>
|
<left>
|
||||||
</left>
|
</left>
|
||||||
<stylesheets>
|
<stylesheets>
|
||||||
<URL value="@/ninja/javafx/smartcsv/fx/smartcsv.css" />
|
<URL value="@/ninja/javafx/smartcsv/fx/smartcsv.css" />
|
||||||
</stylesheets>
|
</stylesheets>
|
||||||
|
<bottom>
|
||||||
|
<GridPane hgap="8.0" BorderPane.alignment="CENTER">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="NEVER" minWidth="10.0" />
|
||||||
|
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
<ColumnConstraints hgrow="NEVER" minWidth="10.0" />
|
||||||
|
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
<ColumnConstraints hgrow="NEVER" minWidth="10.0" />
|
||||||
|
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<Label text="%stateline.csv" GridPane.hgrow="NEVER" />
|
||||||
|
<Label fx:id="csvName" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" />
|
||||||
|
<Label text="%stateline.state" GridPane.columnIndex="2" GridPane.hgrow="NEVER" />
|
||||||
|
<Label fx:id="stateName" GridPane.columnIndex="3" GridPane.hgrow="ALWAYS" />
|
||||||
|
<Label text="%stateline.configuration" GridPane.columnIndex="4" GridPane.hgrow="NEVER" />
|
||||||
|
<Label fx:id="configurationName" GridPane.columnIndex="5" GridPane.hgrow="ALWAYS" />
|
||||||
|
</children>
|
||||||
|
<BorderPane.margin>
|
||||||
|
<Insets top="4.0" left="8.0" bottom="4.0" right="8.0" />
|
||||||
|
</BorderPane.margin>
|
||||||
|
</GridPane>
|
||||||
|
</bottom>
|
||||||
</BorderPane>
|
</BorderPane>
|
||||||
|
|||||||
@@ -9,6 +9,17 @@ menu.edit = Edit
|
|||||||
menu.help = Help
|
menu.help = Help
|
||||||
title.validation.errors = Validation Errors:
|
title.validation.errors = Validation Errors:
|
||||||
|
|
||||||
|
stateline.csv = CSV:
|
||||||
|
stateline.configuration = Validation Configuration:
|
||||||
|
stateline.state = State:
|
||||||
|
|
||||||
|
state.changed = changed
|
||||||
|
state.unchanged = unchanged
|
||||||
|
|
||||||
|
dialog.exit.title = Close Application
|
||||||
|
dialog.exit.header.text = Do you want to close application?
|
||||||
|
dialog.exit.text = There are changes made to the csv file. If you close now, the changes are lost!
|
||||||
|
|
||||||
# validaton messages
|
# validaton messages
|
||||||
validation.message.not.empty = should not be empty
|
validation.message.not.empty = should not be empty
|
||||||
validation.message.integer = should be an integer
|
validation.message.integer = should be an integer
|
||||||
|
|||||||
@@ -17,6 +17,17 @@ menu.edit = Bearbeiten
|
|||||||
menu.help = Hilfe
|
menu.help = Hilfe
|
||||||
title.validation.errors = Fehler in der Datei:
|
title.validation.errors = Fehler in der Datei:
|
||||||
|
|
||||||
|
stateline.csv = CSV:
|
||||||
|
stateline.configuration = Pr\u00fcfkonfiguration:
|
||||||
|
stateline.state = Status:
|
||||||
|
|
||||||
|
state.changed = Ge\u00e4ndert
|
||||||
|
state.unchanged = Unver\u00e4ndert
|
||||||
|
|
||||||
|
dialog.exit.title = Anwendung beenden
|
||||||
|
dialog.exit.header.text = M\u00f6chten Sie wirklich die Anwendung beenden?
|
||||||
|
dialog.exit.text = Es gibt noch ungespeicherte \u00c4nderungen, die verloren gehen, wenn Sie die Anwendung jetzt beenden.
|
||||||
|
|
||||||
# validaton messages
|
# validaton messages
|
||||||
validation.message.not.empty = Darf nicht leer sein.
|
validation.message.not.empty = Darf nicht leer sein.
|
||||||
validation.message.integer = Muss eine Zahl sein.
|
validation.message.integer = Muss eine Zahl sein.
|
||||||
|
|||||||
Reference in New Issue
Block a user