diff --git a/README.md b/README.md index 16dd0e9..37cbf1a 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,11 @@ even in a "normal" CSV editor. So I decided to write this simple JavaFX applicat ##Video [![short video about the application](http://img.youtube.com/vi/SH0UAtPG6Eg/0.jpg)](https://youtu.be/SH0UAtPG6Eg) +##Links +[GitHub Page](http://frosch95.github.io/SmartCSV.fx/) +[Wiki & Documentation](https://github.com/frosch95/SmartCSV.fx/wiki) +binary distribution of the [latest release (0.4)](https://drive.google.com/open?id=0BwY9gBUvn5qmREdCc0FvNDNEQTA) + ##License ###The MIT License (MIT) diff --git a/build.gradle b/build.gradle index 4206848..df15b72 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'ninja.javafx' -version '0.3-SNAPSHOT' +version '0.4-SNAPSHOT' apply plugin: 'java' apply plugin: 'groovy' @@ -22,7 +22,12 @@ dependencies { compile group: 'org.springframework', name:'spring-context', version: '4.3.1.RELEASE' compile group: 'net.sf.supercsv', name: 'super-csv', version: '2.4.0' compile group: 'commons-validator', name: 'commons-validator', version: '1.5.1' - compile group: 'de.jensd', name: 'fontawesomefx', version: '8.9' + compile group: 'de.jensd', name: 'fontawesomefx-commons', version: '8.12' + compile group: 'de.jensd', name: 'fontawesomefx-fontawesome', version: '4.6.3' + compile group: 'de.jensd', name: 'fontawesomefx-materialdesignfont', version: '1.6.50' + compile group: 'de.jensd', name: 'fontawesomefx-materialicons', version: '2.2.0' compile group: 'org.controlsfx', name: 'controlsfx', version: '8.40.11' compile group: 'com.google.code.gson', name: 'gson', version: '2.7' + compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.6.2' + compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.6.2' } diff --git a/src/main/java/ninja/javafx/smartcsv/FileReader.java b/src/main/java/ninja/javafx/smartcsv/FileReader.java index 2a4cb87..b320a03 100644 --- a/src/main/java/ninja/javafx/smartcsv/FileReader.java +++ b/src/main/java/ninja/javafx/smartcsv/FileReader.java @@ -32,6 +32,7 @@ import java.io.IOException; /** * read some file */ -public interface FileReader { +public interface FileReader { + E getContent(); void read(File filename) throws IOException; } diff --git a/src/main/java/ninja/javafx/smartcsv/FileWriter.java b/src/main/java/ninja/javafx/smartcsv/FileWriter.java index e4dd45e..42241f5 100644 --- a/src/main/java/ninja/javafx/smartcsv/FileWriter.java +++ b/src/main/java/ninja/javafx/smartcsv/FileWriter.java @@ -32,6 +32,7 @@ import java.io.IOException; /** * write some file */ -public interface FileWriter { +public interface FileWriter { + void setContent(E content); void write(File filename) throws IOException; } diff --git a/src/main/java/ninja/javafx/smartcsv/csv/CSVFileReader.java b/src/main/java/ninja/javafx/smartcsv/csv/CSVFileReader.java index fb6f63a..a48570f 100644 --- a/src/main/java/ninja/javafx/smartcsv/csv/CSVFileReader.java +++ b/src/main/java/ninja/javafx/smartcsv/csv/CSVFileReader.java @@ -40,8 +40,7 @@ import java.util.Map; /** * reads the csv file and stores the values in csv model */ -@Service -public class CSVFileReader extends CSVConfigurable implements FileReader { +public class CSVFileReader extends CSVConfigurable implements FileReader { private CSVModel model; @@ -72,7 +71,7 @@ public class CSVFileReader extends CSVConfigurable implements FileReader { } } - public CSVModel getData() { + public CSVModel getContent() { return model; } diff --git a/src/main/java/ninja/javafx/smartcsv/csv/CSVFileWriter.java b/src/main/java/ninja/javafx/smartcsv/csv/CSVFileWriter.java index fc173f9..9e63ccf 100644 --- a/src/main/java/ninja/javafx/smartcsv/csv/CSVFileWriter.java +++ b/src/main/java/ninja/javafx/smartcsv/csv/CSVFileWriter.java @@ -42,12 +42,11 @@ import static java.util.stream.Collectors.toMap; /** * filewriter for the csv */ -@Service -public class CSVFileWriter extends CSVConfigurable implements ninja.javafx.smartcsv.FileWriter { +public class CSVFileWriter extends CSVConfigurable implements ninja.javafx.smartcsv.FileWriter { private CSVModel model; - public void setModel(CSVModel model) { + public void setContent(CSVModel model) { this.model = model; } diff --git a/src/main/java/ninja/javafx/smartcsv/files/FileStorage.java b/src/main/java/ninja/javafx/smartcsv/files/FileStorage.java new file mode 100644 index 0000000..1fc41b4 --- /dev/null +++ b/src/main/java/ninja/javafx/smartcsv/files/FileStorage.java @@ -0,0 +1,78 @@ +package ninja.javafx.smartcsv.files; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleObjectProperty; +import ninja.javafx.smartcsv.FileReader; +import ninja.javafx.smartcsv.FileWriter; + +import java.io.File; +import java.io.IOException; + +/** + * This class stores files and there state + * @author abi + */ +public class FileStorage { + + private FileReader reader; + private FileWriter writer; + + public FileStorage(FileReader reader, FileWriter writer) { + this.reader = reader; + this.writer = writer; + } + + private BooleanProperty fileChanged = new SimpleBooleanProperty(true); + private ObjectProperty file = new SimpleObjectProperty<>(); + private ObjectProperty content = new SimpleObjectProperty(); + + public boolean isFileChanged() { + return fileChanged.get(); + } + + public BooleanProperty fileChangedProperty() { + return fileChanged; + } + + public void setFileChanged(boolean fileChanged) { + this.fileChanged.set(fileChanged); + } + + public File getFile() { + return file.get(); + } + + public ObjectProperty fileProperty() { + return file; + } + + public void setFile(File file) { + this.file.set(file); + } + + public E getContent() { + return content.get(); + } + + public ObjectProperty contentProperty() { + return content; + } + + public void setContent(E content) { + this.content.set(content); + } + + public void load() throws IOException { + reader.read(file.get()); + setContent(reader.getContent()); + setFileChanged(false); + } + + public void save() throws IOException { + writer.setContent(content.get()); + writer.write(file.get()); + setFileChanged(false); + } +} diff --git a/src/main/java/ninja/javafx/smartcsv/fx/SmartCSVController.java b/src/main/java/ninja/javafx/smartcsv/fx/SmartCSVController.java index ac8c20b..7833e8a 100644 --- a/src/main/java/ninja/javafx/smartcsv/fx/SmartCSVController.java +++ b/src/main/java/ninja/javafx/smartcsv/fx/SmartCSVController.java @@ -26,10 +26,6 @@ package ninja.javafx.smartcsv.fx; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleObjectProperty; import javafx.collections.ListChangeListener; import javafx.collections.WeakListChangeListener; import javafx.concurrent.WorkerStateEvent; @@ -41,10 +37,9 @@ import javafx.scene.control.*; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.BorderPane; import javafx.stage.FileChooser; -import ninja.javafx.smartcsv.FileReader; -import ninja.javafx.smartcsv.FileWriter; import ninja.javafx.smartcsv.csv.CSVFileReader; import ninja.javafx.smartcsv.csv.CSVFileWriter; +import ninja.javafx.smartcsv.files.FileStorage; import ninja.javafx.smartcsv.fx.about.AboutController; import ninja.javafx.smartcsv.fx.list.ErrorSideBar; import ninja.javafx.smartcsv.fx.preferences.PreferencesController; @@ -58,6 +53,7 @@ import ninja.javafx.smartcsv.fx.util.SaveFileService; import ninja.javafx.smartcsv.fx.validation.ValidationEditorController; import ninja.javafx.smartcsv.preferences.PreferencesFileReader; import ninja.javafx.smartcsv.preferences.PreferencesFileWriter; +import ninja.javafx.smartcsv.validation.ValidationConfiguration; import ninja.javafx.smartcsv.validation.ValidationError; import ninja.javafx.smartcsv.validation.ValidationFileReader; import ninja.javafx.smartcsv.validation.ValidationFileWriter; @@ -103,24 +99,6 @@ public class SmartCSVController extends FXMLController { // injections //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - @Autowired - private PreferencesFileReader preferencesLoader; - - @Autowired - private PreferencesFileWriter preferencesWriter; - - @Autowired - private CSVFileReader csvLoader; - - @Autowired - private ValidationFileReader validationLoader; - - @Autowired - private CSVFileWriter csvFileWriter; - - @Autowired - private ValidationFileWriter validationFileWriter; - @Autowired private AboutController aboutController; @@ -134,7 +112,7 @@ public class SmartCSVController extends FXMLController { private LoadFileService loadFileService; @Autowired - private SaveFileService saveFileService;; + private SaveFileService saveFileService; @FXML private BorderPane applicationPane; @@ -157,6 +135,9 @@ public class SmartCSVController extends FXMLController { @FXML private MenuItem saveAsMenuItem; + @FXML + private MenuItem createConfigMenuItem; + @FXML private MenuItem loadConfigMenuItem; @@ -178,6 +159,9 @@ public class SmartCSVController extends FXMLController { @FXML private Button saveAsButton; + @FXML + private Button createConfigButton; + @FXML private Button loadConfigButton; @@ -199,13 +183,13 @@ public class SmartCSVController extends FXMLController { private ValidationCellFactory cellFactory; - private CSVModel model; private TableView tableView; private ErrorSideBar errorSideBar; - private BooleanProperty fileChanged = new SimpleBooleanProperty(true); private ResourceBundle resourceBundle; - private ObjectProperty currentCsvFile = new SimpleObjectProperty<>(); - private ObjectProperty currentConfigFile= new SimpleObjectProperty<>(); + + private FileStorage currentCsvFile = new FileStorage<>(new CSVFileReader(), new CSVFileWriter()); + private FileStorage currentConfigFile = new FileStorage<>(new ValidationFileReader(), new ValidationFileWriter()); + private FileStorage csvPreferenceFile = new FileStorage<>(new PreferencesFileReader(), new PreferencesFileWriter()); private ListChangeListener errorListListener = c -> tableView.refresh(); private WeakListChangeListener weakErrorListListener = new WeakListChangeListener<>(errorListListener); @@ -221,15 +205,17 @@ public class SmartCSVController extends FXMLController { setupTableCellFactory(); setupErrorSideBar(resourceBundle); - bindMenuItemsToFileExistence(currentCsvFile, saveMenuItem, saveAsMenuItem, addRowMenuItem, loadConfigMenuItem); - bindButtonsToFileExistence(currentCsvFile, saveButton, saveAsButton, addRowButton, loadConfigButton); + bindMenuItemsToContentExistence(currentCsvFile, saveMenuItem, saveAsMenuItem, addRowMenuItem, createConfigMenuItem, loadConfigMenuItem); + bindButtonsToContentExistence(currentCsvFile, saveButton, saveAsButton, addRowButton, createConfigButton, loadConfigButton); - bindMenuItemsToFileExistence(currentConfigFile, saveConfigMenuItem, saveAsConfigMenuItem); - bindButtonsToFileExistence(currentConfigFile, saveAsConfigButton, saveConfigButton); + bindMenuItemsToContentExistence(currentConfigFile, saveConfigMenuItem, saveAsConfigMenuItem); + bindButtonsToContentExistence(currentConfigFile, saveAsConfigButton, saveConfigButton); bindCsvFileName(); bindConfigFileName(); + csvPreferenceFile.setFile(PREFERENCES_FILE); + loadCsvPreferencesFromFile(); } @@ -263,58 +249,43 @@ public class SmartCSVController extends FXMLController { @FXML public void openCsv(ActionEvent actionEvent) { - currentCsvFile.setValue( - loadFile( - csvLoader, - CSV_FILTER_TEXT, - CSV_FILTER_EXTENSION, - "Open CSV", - currentCsvFile.getValue())); + loadFile(CSV_FILTER_TEXT, CSV_FILTER_EXTENSION, "Open CSV", currentCsvFile); } @FXML public void openConfig(ActionEvent actionEvent) { - currentConfigFile.setValue( - loadFile( - validationLoader, - JSON_FILTER_TEXT, - JSON_FILTER_EXTENSION, - "Open Validation Configuration", - currentConfigFile.getValue())); + loadFile(JSON_FILTER_TEXT, JSON_FILTER_EXTENSION, "Open Validation Configuration", currentConfigFile); + } + + @FXML + public void createConfig(ActionEvent actionEvent) { + currentConfigFile.setContent(currentCsvFile.getContent().createValidationConfiguration()); + currentConfigFile.setFile(null); + currentConfigFile.setFileChanged(true); } @FXML public void saveCsv(ActionEvent actionEvent) { - csvFileWriter.setModel(model); - useSaveFileService(csvFileWriter, currentCsvFile.getValue()); + useSaveFileService(currentCsvFile); } @FXML public void saveAsCsv(ActionEvent actionEvent) { - csvFileWriter.setModel(model); - currentCsvFile.setValue( - saveFile( - csvFileWriter, - CSV_FILTER_TEXT, - CSV_FILTER_EXTENSION, - currentCsvFile.getValue())); + saveFile(CSV_FILTER_TEXT, CSV_FILTER_EXTENSION, currentCsvFile); } @FXML public void saveConfig(ActionEvent actionEvent) { - validationFileWriter.setValidationConfiguration(validationLoader.getValidationConfiguration()); - useSaveFileService(validationFileWriter, currentConfigFile.getValue()); + if (currentConfigFile.getFile() == null) { + saveAsConfig(actionEvent); + } else { + useSaveFileService(currentConfigFile); + } } @FXML public void saveAsConfig(ActionEvent actionEvent) { - validationFileWriter.setValidationConfiguration(validationLoader.getValidationConfiguration()); - currentConfigFile.setValue( - saveFile( - validationFileWriter, - JSON_FILTER_TEXT, - JSON_FILTER_EXTENSION, - currentConfigFile.getValue())); + saveFile(JSON_FILTER_TEXT, JSON_FILTER_EXTENSION, currentConfigFile); } @FXML @@ -351,24 +322,24 @@ public class SmartCSVController extends FXMLController { setCsvPreference(csvPreference); saveCsvPreferences(csvPreference); } else { - preferencesController.setCsvPreference(preferencesLoader.getCSVpreference()); + preferencesController.setCsvPreference(csvPreferenceFile.getContent()); } } @FXML public void deleteRow(ActionEvent actionEvent) { - model.getRows().removeAll(tableView.getSelectionModel().getSelectedItems()); - fileChanged.setValue(true); + currentCsvFile.getContent().getRows().removeAll(tableView.getSelectionModel().getSelectedItems()); + currentCsvFile.setFileChanged(true); resetContent(); } @FXML public void addRow(ActionEvent actionEvent) { - CSVRow row = model.addRow(); - for (String column : model.getHeader()) { + CSVRow row = currentCsvFile.getContent().addRow(); + for (String column : currentCsvFile.getContent().getHeader()) { row.addValue(column, ""); } - fileChanged.setValue(true); + currentCsvFile.setFileChanged(true); resetContent(); selectNewRow(); @@ -376,7 +347,7 @@ public class SmartCSVController extends FXMLController { public boolean canExit() { boolean canExit = true; - if (model != null && fileChanged.get()) { + if (currentCsvFile.getContent() != null && currentCsvFile.isFileChanged()) { Alert alert = new Alert(Alert.AlertType.CONFIRMATION); alert.setTitle(resourceBundle.getString("dialog.exit.title")); alert.setHeaderText(resourceBundle.getString("dialog.exit.header.text")); @@ -404,8 +375,8 @@ public class SmartCSVController extends FXMLController { if (result.get() == ButtonType.OK){ runLater(() -> { validationEditorController.updateConfiguration(); - fileChanged.setValue(true); - model.revalidate(); + currentCsvFile.setFileChanged(true); + currentCsvFile.getContent().revalidate(); }); } } @@ -421,15 +392,15 @@ public class SmartCSVController extends FXMLController { tableView.getSelectionModel().select(lastRow); } - private void bindMenuItemsToFileExistence(ObjectProperty file, MenuItem... items) { + private void bindMenuItemsToContentExistence(FileStorage file, MenuItem... items) { for (MenuItem item: items) { - item.disableProperty().bind(isNull(file)); + item.disableProperty().bind(isNull(file.contentProperty())); } } - private void bindButtonsToFileExistence(ObjectProperty file, Button... items) { + private void bindButtonsToContentExistence(FileStorage file, Button... items) { for (Button item: items) { - item.disableProperty().bind(isNull(file)); + item.disableProperty().bind(isNull(file.contentProperty())); } } @@ -446,17 +417,16 @@ public class SmartCSVController extends FXMLController { } private void bindCsvFileName() { - csvName.textProperty().bind(selectString(currentCsvFile, "name")); + csvName.textProperty().bind(selectString(currentCsvFile.fileProperty(), "name")); } private void bindConfigFileName() { - configurationName.textProperty().bind(selectString(currentConfigFile, "name")); + configurationName.textProperty().bind(selectString(currentConfigFile.fileProperty(), "name")); } private void loadCsvPreferencesFromFile() { - if (PREFERENCES_FILE.exists()) { - useLoadFileService(preferencesLoader, PREFERENCES_FILE, - event -> setCsvPreference(preferencesLoader.getCSVpreference())); + if (csvPreferenceFile.getFile().exists()) { + useLoadFileService(csvPreferenceFile, event -> setCsvPreference(csvPreferenceFile.getContent())); } else { setCsvPreference(CsvPreference.EXCEL_NORTH_EUROPE_PREFERENCE); } @@ -465,37 +435,34 @@ public class SmartCSVController extends FXMLController { private void saveCsvPreferences(CsvPreference csvPreference) { try { createPreferenceFile(); - preferencesWriter.setCsvPreference(csvPreference); - useSaveFileService(preferencesWriter, PREFERENCES_FILE); + csvPreferenceFile.setContent(csvPreference); + useSaveFileService(csvPreferenceFile); } catch (IOException e) { e.printStackTrace(); } } private void createPreferenceFile() throws IOException { - if (!PREFERENCES_FILE.exists()) { + if (!csvPreferenceFile.getFile().exists()) { createPreferencesFileFolder(); - PREFERENCES_FILE.createNewFile(); + csvPreferenceFile.getFile().createNewFile(); } } private void createPreferencesFileFolder() { - if (!PREFERENCES_FILE.getParentFile().exists()) { - PREFERENCES_FILE.getParentFile().mkdir(); + if (!csvPreferenceFile.getFile().getParentFile().exists()) { + csvPreferenceFile.getFile().getParentFile().mkdir(); } } private void setCsvPreference(CsvPreference csvPreference) { - csvLoader.setCsvPreference(csvPreference); - csvFileWriter.setCsvPreference(csvPreference); preferencesController.setCsvPreference(csvPreference); } - private File loadFile(FileReader fileReader, - String filterText, + private void loadFile(String filterText, String filter, String title, - File initChildFile) { + FileStorage storageFile) { final FileChooser fileChooser = new FileChooser(); //Set extension filter @@ -503,83 +470,73 @@ public class SmartCSVController extends FXMLController { fileChooser.getExtensionFilters().add(extFilter); fileChooser.setTitle(title); - if (initChildFile != null) { - fileChooser.setInitialDirectory(initChildFile.getParentFile()); + if (storageFile.getFile() != null) { + fileChooser.setInitialDirectory(storageFile.getFile().getParentFile()); } //Show open file dialog File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow()); if (file != null) { - useLoadFileService(fileReader, file, event -> runLater(() -> { - resetContent(); - fileChanged.setValue(false); - })); - return file; - } else { - return initChildFile; + storageFile.setFile(file); + useLoadFileService(storageFile, t -> resetContent()); } } - private File saveFile(FileWriter writer, String filterText, String filter, File initFile) { - File file = initFile; - if (model != null) { + private File saveFile(String filterText, String filter, FileStorage fileStorage) { + File file = fileStorage.getFile(); + if (fileStorage.getContent() != null) { final FileChooser fileChooser = new FileChooser(); //Set extension filter final FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(filterText, filter); fileChooser.getExtensionFilters().add(extFilter); - if (initFile != null) { - fileChooser.setInitialDirectory(initFile.getParentFile()); - fileChooser.setInitialFileName(initFile.getName()); + if (fileStorage.getFile() != null) { + fileChooser.setInitialDirectory(fileStorage.getFile().getParentFile()); + fileChooser.setInitialFileName(fileStorage.getFile().getName()); } fileChooser.setTitle("Save File"); //Show open file dialog file = fileChooser.showSaveDialog(applicationPane.getScene().getWindow()); if (file != null) { - useSaveFileService(writer, file); + fileStorage.setFile(file); + useSaveFileService(fileStorage); } } return file; } - private void useLoadFileService(FileReader fileReader, File file, EventHandler value) { - loadFileService.setFile(file); - loadFileService.setFileReader(fileReader); + private void useLoadFileService(FileStorage fileStorage, EventHandler onSucceededHandler) { + loadFileService.setFileStorage(fileStorage); loadFileService.restart(); - loadFileService.setOnSucceeded(value); + loadFileService.setOnSucceeded(onSucceededHandler); } - private void useSaveFileService(FileWriter writer, File file) { - saveFileService.setFile(file); - saveFileService.setWriter(writer); + private void useSaveFileService(FileStorage fileStorage) { + saveFileService.setFileStorage(fileStorage); saveFileService.restart(); - saveFileService.setOnSucceeded(event -> runLater(() -> { - resetContent(); - fileChanged.setValue(false); - })); + saveFileService.setOnSucceeded(t -> resetContent()); } /** * Creates new table view and add the new content */ private void resetContent() { - model = csvLoader.getData(); - if (model != null) { - model.getValidationError().addListener(weakErrorListListener); - model.setValidationConfiguration(validationLoader.getValidationConfiguration()); - validationEditorController.setValidationConfiguration(validationLoader.getValidationConfiguration()); + if (currentCsvFile.getContent() != null) { + currentCsvFile.getContent().getValidationError().addListener(weakErrorListListener); + currentCsvFile.getContent().setValidationConfiguration(currentConfigFile.getContent()); + validationEditorController.setValidationConfiguration(currentConfigFile.getContent()); tableView = new TableView<>(); bindMenuItemsToTableSelection(deleteRowMenuItem); bindButtonsToTableSelection(deleteRowButton); - for (String column : model.getHeader()) { + for (String column : currentCsvFile.getContent().getHeader()) { addColumn(column, tableView); } - tableView.getItems().setAll(model.getRows()); + tableView.getItems().setAll(currentCsvFile.getContent().getRows()); tableView.setEditable(true); setBottomAnchor(tableView, 0.0); @@ -587,7 +544,7 @@ public class SmartCSVController extends FXMLController { setLeftAnchor(tableView, 0.0); setRightAnchor(tableView, 0.0); tableWrapper.getChildren().setAll(tableView); - errorSideBar.setModel(model); + errorSideBar.setModel(currentCsvFile.getContent()); } } @@ -612,8 +569,8 @@ public class SmartCSVController extends FXMLController { event.getTableView().getItems().get(event.getTablePosition().getRow()). getColumns().get(header).setValue(event.getNewValue()); runLater(() -> { - fileChanged.setValue(true); - model.revalidate(); + currentCsvFile.setFileChanged(true); + currentCsvFile.getContent().revalidate(); }); } }); @@ -624,7 +581,7 @@ public class SmartCSVController extends FXMLController { private ContextMenu contextMenuForColumn(String header) { ContextMenu contextMenu = new ContextMenu(); MenuItem editColumnRulesMenuItem = new MenuItem(resourceBundle.getString("context.menu.edit.column.rules")); - bindMenuItemsToFileExistence(currentConfigFile, editColumnRulesMenuItem); + bindMenuItemsToContentExistence(currentConfigFile, editColumnRulesMenuItem); editColumnRulesMenuItem.setOnAction(e -> showValidationEditor(header)); contextMenu.getItems().addAll(editColumnRulesMenuItem); return contextMenu; diff --git a/src/main/java/ninja/javafx/smartcsv/fx/list/ErrorSideBar.java b/src/main/java/ninja/javafx/smartcsv/fx/list/ErrorSideBar.java index 24339f4..cca48f6 100644 --- a/src/main/java/ninja/javafx/smartcsv/fx/list/ErrorSideBar.java +++ b/src/main/java/ninja/javafx/smartcsv/fx/list/ErrorSideBar.java @@ -38,6 +38,8 @@ import javafx.scene.text.Text; import ninja.javafx.smartcsv.fx.table.model.CSVModel; import ninja.javafx.smartcsv.fx.util.ColorConstants; import ninja.javafx.smartcsv.validation.ValidationError; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.controlsfx.control.PopOver; import java.util.ArrayList; @@ -54,6 +56,8 @@ import static ninja.javafx.smartcsv.fx.util.I18nValidationUtil.getI18nValidatioM */ public class ErrorSideBar extends Region { + private static final Logger logger = LogManager.getLogger(ErrorSideBar.class); + private static final double WIDTH = 20.0; private static final int BORDER = 8; private static final double STATUS_BLOCK_HEIGHT = WIDTH - BORDER; @@ -133,7 +137,7 @@ public class ErrorSideBar extends Region { statusBlock.setStyle("-fx-background-color: " + ERROR_COLOR); int rows = model.get().getRows().size(); - double space = heightWithoutStatusBlock() / rows; + double space = (double)heightWithoutStatusBlock() / rows; for (ValidationError error : errorList) { errorMarkerList.add(generateErrorMarker(space, error)); } @@ -147,6 +151,8 @@ public class ErrorSideBar extends Region { } private Region generateErrorMarker(double space, ValidationError error) { + logger.info("generate error marker for {} errors in line {}", error.getMessages().size(), error.getLineNumber()); + logger.info("layout y is set to {}", (space * error.getLineNumber() + STATUS_BLOCK_OFFSET)); Region errorMarker = new Region(); errorMarker.setLayoutY(space * error.getLineNumber() + STATUS_BLOCK_OFFSET); errorMarker.setPrefSize(WIDTH, 2); diff --git a/src/main/java/ninja/javafx/smartcsv/fx/table/model/CSVModel.java b/src/main/java/ninja/javafx/smartcsv/fx/table/model/CSVModel.java index 079609f..72e97f0 100644 --- a/src/main/java/ninja/javafx/smartcsv/fx/table/model/CSVModel.java +++ b/src/main/java/ninja/javafx/smartcsv/fx/table/model/CSVModel.java @@ -28,9 +28,16 @@ package ninja.javafx.smartcsv.fx.table.model; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javafx.concurrent.Service; +import javafx.concurrent.Task; import ninja.javafx.smartcsv.validation.ValidationConfiguration; import ninja.javafx.smartcsv.validation.ValidationError; import ninja.javafx.smartcsv.validation.Validator; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayList; +import java.util.List; /** * The CSVModel is the client representation for the csv filepath. @@ -38,10 +45,13 @@ import ninja.javafx.smartcsv.validation.Validator; */ public class CSVModel { + private static final Logger logger = LogManager.getLogger(CSVModel.class); + private Validator validator; private ObservableList rows = FXCollections.observableArrayList(); private String[] header; private ObservableList validationError = FXCollections.observableArrayList(); + private RevalidationService revalidationService = new RevalidationService(); /** * sets the validator configuration for the data revalidates @@ -100,34 +110,86 @@ public class CSVModel { public void revalidate() { validationError.clear(); - if (header != null && validator != null) { - addValidationError(validator.isHeaderValid(header)); - } + logger.info("revalidate: hasValidator -> {}", hasValidator()); - for (int lineNumber = 0; lineNumber < rows.size(); lineNumber++) { - CSVRow row = rows.get(lineNumber); - row.setValidator(validator); - for (String column: row.getColumns().keySet()) { - CSVValue value = row.getColumns().get(column).getValue(); - value.setValidator(validator); - if (validator != null) { - ValidationError validationError = validator.isValid(column, value.getValue(), lineNumber); - if (validationError != null) { - addValidationError(validationError); - value.setValidationError(validationError); - } else { - value.setValidationError(null); - } - } else { - value.setValidationError(null); - } - } - } + if (!hasValidator()) return; + + revalidationService.setHeader(header); + revalidationService.setRows(rows); + revalidationService.setValidator(validator); + revalidationService.setOnSucceeded(t -> validationError.setAll(revalidationService.getValue())); + revalidationService.setOnFailed(t -> logger.error("revalidation service failed!")); + revalidationService.restart(); } - private void addValidationError(ValidationError validationError) { - if (validationError != null) { - this.validationError.add(validationError); + private boolean hasValidator() { + return validator != null && validator.hasConfig(); + } + + public ValidationConfiguration createValidationConfiguration() { + ValidationConfiguration newValidationConfiguration = new ValidationConfiguration(); + newValidationConfiguration.setHeaderNames(this.header); + this.validator = new Validator(newValidationConfiguration); + this.revalidate(); + return newValidationConfiguration; + } + + private static class RevalidationService extends Service> { + + private Validator validator; + private List rows; + private String[] header; + + public void setValidator(Validator validator) { + this.validator = validator; + } + + public void setRows(List rows) { + this.rows = rows; + } + + public void setHeader(String[] header) { + this.header = header; + } + + @Override + protected Task> createTask() { + return new Task>() { + @Override + protected List call() throws Exception { + List errors = new ArrayList<>(); + + if (header != null) { + ValidationError headerError = validator.isHeaderValid(header); + if (headerError != null) { + logger.info("revalidate: header error found"); + errors.add(headerError); + } + } + + for (int lineNumber = 0; lineNumber < rows.size(); lineNumber++) { + CSVRow row = rows.get(lineNumber); + row.setValidator(validator); + for (String column: row.getColumns().keySet()) { + CSVValue value = row.getColumns().get(column).getValue(); + value.setValidator(validator); + if (validator != null) { + ValidationError validationError = validator.isValid(column, value.getValue(), lineNumber); + if (validationError != null) { + logger.info("revalidate: {} errors found in line {}", validationError.getMessages().size(), lineNumber); + errors.add(validationError); + value.setValidationError(validationError); + } else { + value.setValidationError(null); + } + } else { + value.setValidationError(null); + } + } + } + return errors; + } + }; } } diff --git a/src/main/java/ninja/javafx/smartcsv/fx/util/LoadFileService.java b/src/main/java/ninja/javafx/smartcsv/fx/util/LoadFileService.java index d8269ac..3aa3335 100644 --- a/src/main/java/ninja/javafx/smartcsv/fx/util/LoadFileService.java +++ b/src/main/java/ninja/javafx/smartcsv/fx/util/LoadFileService.java @@ -29,6 +29,7 @@ package ninja.javafx.smartcsv.fx.util; import javafx.concurrent.Service; import javafx.concurrent.Task; import ninja.javafx.smartcsv.FileReader; +import ninja.javafx.smartcsv.files.FileStorage; import java.io.File; @@ -38,14 +39,10 @@ import java.io.File; @org.springframework.stereotype.Service public class LoadFileService extends Service { - private File file; - private FileReader fileReader; + private FileStorage file; - public void setFile(File value) { - file = value; - } - public void setFileReader(FileReader fileReader) { - this.fileReader = fileReader; + public void setFileStorage(FileStorage file) { + this.file = file; } @Override @@ -54,7 +51,7 @@ public class LoadFileService extends Service { @Override protected Void call() throws Exception { if (file != null) { - fileReader.read(file); + file.load(); } return null; } diff --git a/src/main/java/ninja/javafx/smartcsv/fx/util/SaveFileService.java b/src/main/java/ninja/javafx/smartcsv/fx/util/SaveFileService.java index 3941995..86c6295 100644 --- a/src/main/java/ninja/javafx/smartcsv/fx/util/SaveFileService.java +++ b/src/main/java/ninja/javafx/smartcsv/fx/util/SaveFileService.java @@ -30,6 +30,7 @@ import javafx.concurrent.Service; import javafx.concurrent.Task; import ninja.javafx.smartcsv.FileWriter; import ninja.javafx.smartcsv.csv.CSVFileWriter; +import ninja.javafx.smartcsv.files.FileStorage; import java.io.File; @@ -41,14 +42,9 @@ import static javafx.application.Platform.runLater; @org.springframework.stereotype.Service public class SaveFileService extends Service { - private File file; - private FileWriter writer; + private FileStorage file; - public void setWriter(FileWriter writer) { - this.writer = writer; - } - - public void setFile(File value) { + public void setFileStorage(FileStorage value) { file = value; } @@ -58,7 +54,7 @@ public class SaveFileService extends Service { @Override protected Void call() throws Exception { try { - writer.write(file); + file.save(); } catch (Throwable ex) { ex.printStackTrace(); } diff --git a/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileReader.java b/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileReader.java index a5b32d6..5a9c920 100644 --- a/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileReader.java +++ b/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileReader.java @@ -42,8 +42,7 @@ import static ninja.javafx.smartcsv.preferences.QuoteModeHelper.getQuoteMode; /** * file reader for the preferences */ -@Service -public class PreferencesFileReader implements FileReader { +public class PreferencesFileReader implements FileReader { private Map config; private CsvPreference csvPreference; @@ -74,7 +73,7 @@ public class PreferencesFileReader implements FileReader { } } - public CsvPreference getCSVpreference() { + public CsvPreference getContent() { return csvPreference; } diff --git a/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileWriter.java b/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileWriter.java index 53d383f..9b70649 100644 --- a/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileWriter.java +++ b/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileWriter.java @@ -41,12 +41,11 @@ import java.util.Map; /** * Save preferences to configuration file */ -@Service -public class PreferencesFileWriter implements FileWriter { +public class PreferencesFileWriter implements FileWriter { private CsvPreference csvPreference; - public void setCsvPreference(CsvPreference csvPreference) { + public void setContent(CsvPreference csvPreference) { this.csvPreference = csvPreference; } diff --git a/src/main/java/ninja/javafx/smartcsv/validation/HeaderConfiguration.java b/src/main/java/ninja/javafx/smartcsv/validation/HeaderConfiguration.java index f5d1256..1bcabea 100644 --- a/src/main/java/ninja/javafx/smartcsv/validation/HeaderConfiguration.java +++ b/src/main/java/ninja/javafx/smartcsv/validation/HeaderConfiguration.java @@ -39,4 +39,8 @@ public class HeaderConfiguration { public String[] getNames() { return names; } + + public void setNames(String[] names) { + this.names = names; + } } diff --git a/src/main/java/ninja/javafx/smartcsv/validation/ValidationConfiguration.java b/src/main/java/ninja/javafx/smartcsv/validation/ValidationConfiguration.java index 029144d..ebb5ca2 100644 --- a/src/main/java/ninja/javafx/smartcsv/validation/ValidationConfiguration.java +++ b/src/main/java/ninja/javafx/smartcsv/validation/ValidationConfiguration.java @@ -32,8 +32,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import static java.lang.Boolean.FALSE; - /** * validation configuration */ @@ -50,6 +48,10 @@ public class ValidationConfiguration { return headerConfiguration.getNames(); } + public void setHeaderNames(String[] headerNames) { + headerConfiguration.setNames(headerNames); + } + public Boolean getIntegerRuleFor(String column) { return (Boolean)getValue(column, "integer"); } diff --git a/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileReader.java b/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileReader.java index fdd1acd..6d4ede7 100644 --- a/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileReader.java +++ b/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileReader.java @@ -36,8 +36,7 @@ import java.io.IOException; /** * This class loads the constraints as json config */ -@Service -public class ValidationFileReader implements FileReader { +public class ValidationFileReader implements FileReader { private ValidationConfiguration config; @@ -46,7 +45,7 @@ public class ValidationFileReader implements FileReader { config = new GsonBuilder().create().fromJson(new java.io.FileReader(file), ValidationConfiguration.class); } - public ValidationConfiguration getValidationConfiguration() { + public ValidationConfiguration getContent() { return config; } } diff --git a/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileWriter.java b/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileWriter.java index 7bcdf6d..8fe2a49 100644 --- a/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileWriter.java +++ b/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileWriter.java @@ -38,12 +38,11 @@ import java.nio.file.Files; /** * file writer for the validation configuration */ -@Service -public class ValidationFileWriter implements FileWriter { +public class ValidationFileWriter implements FileWriter { private ValidationConfiguration validationConfiguration; - public void setValidationConfiguration(ValidationConfiguration validationConfiguration) { + public void setContent(ValidationConfiguration validationConfiguration) { this.validationConfiguration = validationConfiguration; } diff --git a/src/main/java/ninja/javafx/smartcsv/validation/Validator.java b/src/main/java/ninja/javafx/smartcsv/validation/Validator.java index bdb466a..e0f211d 100644 --- a/src/main/java/ninja/javafx/smartcsv/validation/Validator.java +++ b/src/main/java/ninja/javafx/smartcsv/validation/Validator.java @@ -67,7 +67,7 @@ public class Validator { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // oublic methods + // public methods //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** @@ -78,7 +78,7 @@ public class Validator { */ public ValidationError isValid(String column, String value, Integer lineNumber) { ValidationError result = null; - if (validationConfig != null) { + if (hasConfig()) { ValidationError error = ValidationError.withLineNumber(lineNumber); checkBlankOrNull(column, value, error); @@ -101,6 +101,9 @@ public class Validator { return result; } + public boolean hasConfig() { + return validationConfig != null; + } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // private methods diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..4c71d59 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,26 @@ + + + + + smartcsv.log + + + + + + + + + + + %d %p %C{1.} [%t] %m%n + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/ninja/javafx/smartcsv/fx/about/about.fxml b/src/main/resources/ninja/javafx/smartcsv/fx/about/about.fxml index f8b5209..8e4516a 100644 --- a/src/main/resources/ninja/javafx/smartcsv/fx/about/about.fxml +++ b/src/main/resources/ninja/javafx/smartcsv/fx/about/about.fxml @@ -57,6 +57,7 @@ + diff --git a/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.css b/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.css index 782de96..77951a5 100644 --- a/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.css +++ b/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.css @@ -15,48 +15,68 @@ } .open-icon { - -glyph-name: "FILE_TEXT_ALT"; - -glyph-size: 14px; + -glyph-name: "FILE_IMPORT"; + -glyph-size: 16px; +} + +.file-document-icon { + -glyph-name: "FILE_DOCUMENT"; + -glyph-size: 16px; } .config-icon { - -glyph-name: "CHECK"; - -glyph-size: 14px; + -glyph-name: "CLIPBOARD"; + -glyph-size: 16px; +} + +.create-config-icon { + -glyph-name: "STAR"; + -glyph-size: 10px; +} + +.load-config-icon { + -glyph-name: "ARROW_UP_BOLD"; + -glyph-size: 10px; +} + +.save-config-icon { + -glyph-name: "ARROW_DOWN_BOLD"; + -glyph-size: 10px; } .save-icon { - -glyph-name: "FLOPPY_ALT"; - -glyph-size: 14px; + -glyph-name: "FILE_EXPORT"; + -glyph-size: 16px; } .exit-icon { - -glyph-name: "SIGN_OUT"; - -glyph-size: 14px; + -glyph-name: "EXIT_TO_APP"; + -glyph-size: 16px; } .info-icon { - -glyph-name: "INFO"; - -glyph-size: 14px; + -glyph-name: "INFORMATION_OUTLINE"; + -glyph-size: 16px; } -.error-title-icon { - -glyph-name: "EXCLAMATION_TRIANGLE"; - -glyph-size: 14px; +.config-check-icon { + -glyph-name: "CLIPBOARD_CHECK"; + -glyph-size: 16px; } .preferences-icon { - -glyph-name: "COG"; - -glyph-size: 14px; + -glyph-name: "SETTINGS"; + -glyph-size: 16px; } .delete-icon { - -glyph-name: "MINUS"; - -glyph-size: 14px; + -glyph-name: "TABLE_ROW_REMOVE"; + -glyph-size: 16px; } .add-icon { - -glyph-name: "PLUS"; - -glyph-size: 14px; + -glyph-name: "TABLE_ROW_PLUS_AFTER"; + -glyph-size: 16px; } /* toolbar customization based on http://fxexperience.com/2012/02/customized-segmented-toolbar-buttons/ */ @@ -91,6 +111,13 @@ -fx-fill: white; } +.menu-item .load-config-icon, +.menu-item .save-config-icon, +.menu-item .create-config-icon +{ + -fx-fill: white; +} + .tool-bar .save-icon { -glyph-size: 16px; -fx-fill: white; diff --git a/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.fxml b/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.fxml index 7fc539b..96d1739 100644 --- a/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.fxml +++ b/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.fxml @@ -1,7 +1,6 @@ - @@ -22,6 +21,7 @@ + @@ -32,57 +32,72 @@ - + - + - + + + + + + + + + + + - + + + + + + - - + + - - - - - - + + + + + + - + - + @@ -91,12 +106,12 @@ - + - + @@ -105,7 +120,7 @@ - + @@ -119,7 +134,7 @@ - + + @@ -203,7 +236,7 @@ - + @@ -248,10 +281,10 @@ - + diff --git a/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.properties b/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.properties index a965d51..6c026c3 100644 --- a/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.properties +++ b/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.properties @@ -1,5 +1,6 @@ menu.open.csv = Open CSV File menu.open.config = Open Validation Config +menu.create.config = Create Validation Config menu.save = Save menu.save.as = Save As ... menu.save.config = Save Validation Config diff --git a/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv_de.properties b/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv_de.properties index c215b9c..cfe414c 100644 --- a/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv_de.properties +++ b/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv_de.properties @@ -8,6 +8,7 @@ menu.open.csv = CSV Datei \u00f6ffnen menu.open.config = Pr\u00fcfkonfiguration \u00f6ffnen +menu.create.config = Pr\u00fcfkonfiguration erzeugen menu.save = Speichern menu.save.as = Speichern als ... menu.save.config = Pr\u00fcfkonfiguration speichern