show state and allow exit based on state

This commit is contained in:
Andreas Billmann
2015-12-18 12:19:19 +01:00
parent 67f92cd60f
commit c87471f0d1
5 changed files with 147 additions and 25 deletions

View File

@@ -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();
}
});
} }
} }

View File

@@ -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 {
} }
}; };
} }
} }
} }

View File

@@ -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>

View File

@@ -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

View File

@@ -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.