mirror of
https://github.com/frosch95/SmartCSV.fx.git
synced 2026-04-11 13:38:23 +02:00
Merge branch 'editable_column_rules'
This commit is contained in:
@@ -21,8 +21,8 @@ dependencies {
|
||||
compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.5'
|
||||
compile group: 'org.springframework', name:'spring-context', version: '4.2.4.RELEASE'
|
||||
compile group: 'net.sf.supercsv', name: 'super-csv', version: '2.4.0'
|
||||
compile group: 'com.typesafe', name: 'config', version: '1.3.0'
|
||||
compile group: 'commons-validator', name: 'commons-validator', version: '1.5.0'
|
||||
compile group: 'de.jensd', name: 'fontawesomefx', version: '8.8'
|
||||
compile group: 'org.controlsfx', name: 'controlsfx', version: '8.40.10'
|
||||
compile group: 'com.google.code.gson', name: 'gson', version: '2.5'
|
||||
}
|
||||
|
||||
@@ -30,6 +30,9 @@ 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;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
@@ -52,10 +55,12 @@ import ninja.javafx.smartcsv.fx.table.model.CSVRow;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
|
||||
import ninja.javafx.smartcsv.fx.util.LoadFileService;
|
||||
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.ValidationError;
|
||||
import ninja.javafx.smartcsv.validation.ValidationFileReader;
|
||||
import ninja.javafx.smartcsv.validation.ValidationFileWriter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -68,6 +73,7 @@ import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
import static java.text.MessageFormat.format;
|
||||
import static javafx.application.Platform.exit;
|
||||
import static javafx.application.Platform.runLater;
|
||||
import static javafx.beans.binding.Bindings.*;
|
||||
@@ -88,6 +94,10 @@ public class SmartCSVController extends FXMLController {
|
||||
".SmartCSV.fx" +
|
||||
File.separator + "" +
|
||||
"preferences.json");
|
||||
public static final String CSV_FILTER_TEXT = "CSV files (*.csv)";
|
||||
public static final String CSV_FILTER_EXTENSION = "*.csv";
|
||||
public static final String JSON_FILTER_TEXT = "JSON files (*.json)";
|
||||
public static final String JSON_FILTER_EXTENSION = "*.json";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// injections
|
||||
@@ -108,12 +118,18 @@ public class SmartCSVController extends FXMLController {
|
||||
@Autowired
|
||||
private CSVFileWriter csvFileWriter;
|
||||
|
||||
@Autowired
|
||||
private ValidationFileWriter validationFileWriter;
|
||||
|
||||
@Autowired
|
||||
private AboutController aboutController;
|
||||
|
||||
@Autowired
|
||||
private PreferencesController preferencesController;
|
||||
|
||||
@Autowired
|
||||
private ValidationEditorController validationEditorController;
|
||||
|
||||
@Autowired
|
||||
private LoadFileService loadFileService;
|
||||
|
||||
@@ -141,6 +157,15 @@ public class SmartCSVController extends FXMLController {
|
||||
@FXML
|
||||
private MenuItem saveAsMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem loadConfigMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem saveConfigMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem saveAsConfigMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem deleteRowMenuItem;
|
||||
|
||||
@@ -153,14 +178,21 @@ public class SmartCSVController extends FXMLController {
|
||||
@FXML
|
||||
private Button saveAsButton;
|
||||
|
||||
@FXML
|
||||
private Button loadConfigButton;
|
||||
|
||||
@FXML
|
||||
private Button saveConfigButton;
|
||||
|
||||
@FXML
|
||||
private Button saveAsConfigButton;
|
||||
|
||||
@FXML
|
||||
private Button deleteRowButton;
|
||||
|
||||
@FXML
|
||||
private Button addRowButton;
|
||||
|
||||
private ErrorSideBar errorSideBar;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// members
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -169,11 +201,14 @@ public class SmartCSVController extends FXMLController {
|
||||
|
||||
private CSVModel model;
|
||||
private TableView<CSVRow> tableView;
|
||||
private ErrorSideBar errorSideBar;
|
||||
private BooleanProperty fileChanged = new SimpleBooleanProperty(true);
|
||||
private ResourceBundle resourceBundle;
|
||||
private ObjectProperty<File> currentCsvFile = new SimpleObjectProperty<>();
|
||||
private ObjectProperty<File> currentConfigFile= new SimpleObjectProperty<>();
|
||||
|
||||
private ListChangeListener<ValidationError> errorListListener = c -> tableView.refresh();
|
||||
private WeakListChangeListener<ValidationError> weakErrorListListener = new WeakListChangeListener<>(errorListListener);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// init
|
||||
@@ -184,22 +219,28 @@ public class SmartCSVController extends FXMLController {
|
||||
this.resourceBundle = resourceBundle;
|
||||
|
||||
setupTableCellFactory();
|
||||
setupErrorSideBar(resourceBundle);
|
||||
|
||||
errorSideBar = new ErrorSideBar(resourceBundle);
|
||||
bindMenuItemsToFileExistence(currentCsvFile, saveMenuItem, saveAsMenuItem, addRowMenuItem, loadConfigMenuItem);
|
||||
bindButtonsToFileExistence(currentCsvFile, saveButton, saveAsButton, addRowButton, loadConfigButton);
|
||||
|
||||
errorSideBar.selectedValidationErrorProperty().addListener((observable, oldValue, newValue) -> {
|
||||
scrollToError(newValue);
|
||||
});
|
||||
applicationPane.setRight(errorSideBar);
|
||||
bindMenuItemsToFileExistence(currentConfigFile, saveConfigMenuItem, saveAsConfigMenuItem);
|
||||
bindButtonsToFileExistence(currentConfigFile, saveAsConfigButton, saveConfigButton);
|
||||
|
||||
bindMenuItemsToCsvFileExtistence(saveMenuItem, saveAsMenuItem, addRowMenuItem);
|
||||
bindButtonsToCsvFileExistence(saveButton, saveAsButton, addRowButton);
|
||||
bindCsvFileName();
|
||||
bindConfigFileName();
|
||||
|
||||
loadCsvPreferencesFromFile();
|
||||
}
|
||||
|
||||
private void setupErrorSideBar(ResourceBundle resourceBundle) {
|
||||
errorSideBar = new ErrorSideBar(resourceBundle);
|
||||
errorSideBar.selectedValidationErrorProperty().addListener((observable, oldValue, newValue) -> {
|
||||
scrollToError(newValue);
|
||||
});
|
||||
applicationPane.setRight(errorSideBar);
|
||||
}
|
||||
|
||||
private void setupTableCellFactory() {
|
||||
cellFactory = new ValidationCellFactory(resourceBundle);
|
||||
}
|
||||
@@ -225,8 +266,8 @@ public class SmartCSVController extends FXMLController {
|
||||
currentCsvFile.setValue(
|
||||
loadFile(
|
||||
csvLoader,
|
||||
"CSV files (*.csv)",
|
||||
"*.csv",
|
||||
CSV_FILTER_TEXT,
|
||||
CSV_FILTER_EXTENSION,
|
||||
"Open CSV",
|
||||
currentCsvFile.getValue()));
|
||||
}
|
||||
@@ -236,8 +277,8 @@ public class SmartCSVController extends FXMLController {
|
||||
currentConfigFile.setValue(
|
||||
loadFile(
|
||||
validationLoader,
|
||||
"JSON files (*.json)",
|
||||
"*.json",
|
||||
JSON_FILTER_TEXT,
|
||||
JSON_FILTER_EXTENSION,
|
||||
"Open Validation Configuration",
|
||||
currentConfigFile.getValue()));
|
||||
}
|
||||
@@ -254,11 +295,28 @@ public class SmartCSVController extends FXMLController {
|
||||
currentCsvFile.setValue(
|
||||
saveFile(
|
||||
csvFileWriter,
|
||||
"CSV files (*.csv)",
|
||||
"*.csv",
|
||||
CSV_FILTER_TEXT,
|
||||
CSV_FILTER_EXTENSION,
|
||||
currentCsvFile.getValue()));
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void saveConfig(ActionEvent actionEvent) {
|
||||
validationFileWriter.setValidationConfiguration(validationLoader.getValidationConfiguration());
|
||||
useSaveFileService(validationFileWriter, currentConfigFile.getValue());
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void saveAsConfig(ActionEvent actionEvent) {
|
||||
validationFileWriter.setValidationConfiguration(validationLoader.getValidationConfiguration());
|
||||
currentConfigFile.setValue(
|
||||
saveFile(
|
||||
validationFileWriter,
|
||||
JSON_FILTER_TEXT,
|
||||
JSON_FILTER_EXTENSION,
|
||||
currentConfigFile.getValue()));
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close(ActionEvent actionEvent) {
|
||||
if (canExit()) {
|
||||
@@ -333,6 +391,25 @@ public class SmartCSVController extends FXMLController {
|
||||
return canExit;
|
||||
}
|
||||
|
||||
public void showValidationEditor(String column) {
|
||||
validationEditorController.setSelectedColumn(column);
|
||||
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
alert.setGraphic(null);
|
||||
alert.setTitle(resourceBundle.getString("dialog.validation.rules.title"));
|
||||
alert.setHeaderText(format(resourceBundle.getString("dialog.validation.rules.header"), column));
|
||||
alert.getDialogPane().setContent(validationEditorController.getView());
|
||||
Optional<ButtonType> result = alert.showAndWait();
|
||||
|
||||
if (result.get() == ButtonType.OK){
|
||||
runLater(() -> {
|
||||
validationEditorController.updateConfiguration();
|
||||
fileChanged.setValue(true);
|
||||
model.revalidate();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// private methods
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -344,15 +421,15 @@ public class SmartCSVController extends FXMLController {
|
||||
tableView.getSelectionModel().select(lastRow);
|
||||
}
|
||||
|
||||
private void bindMenuItemsToCsvFileExtistence(MenuItem... items) {
|
||||
private void bindMenuItemsToFileExistence(ObjectProperty<File> file, MenuItem... items) {
|
||||
for (MenuItem item: items) {
|
||||
item.disableProperty().bind(isNull(currentCsvFile));
|
||||
item.disableProperty().bind(isNull(file));
|
||||
}
|
||||
}
|
||||
|
||||
private void bindButtonsToCsvFileExistence(Button... items) {
|
||||
private void bindButtonsToFileExistence(ObjectProperty<File> file, Button... items) {
|
||||
for (Button item: items) {
|
||||
item.disableProperty().bind(isNull(currentCsvFile));
|
||||
item.disableProperty().bind(isNull(file));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,9 +455,9 @@ public class SmartCSVController extends FXMLController {
|
||||
|
||||
private void loadCsvPreferencesFromFile() {
|
||||
if (PREFERENCES_FILE.exists()) {
|
||||
useLoadFileService(preferencesLoader, PREFERENCES_FILE);
|
||||
useLoadFileService(preferencesLoader, PREFERENCES_FILE,
|
||||
event -> setCsvPreference(preferencesLoader.getCSVpreference()));
|
||||
}
|
||||
setCsvPreference(preferencesLoader.getCSVpreference());
|
||||
}
|
||||
|
||||
private void saveCsvPreferences(CsvPreference csvPreference) {
|
||||
@@ -431,7 +508,10 @@ public class SmartCSVController extends FXMLController {
|
||||
//Show open file dialog
|
||||
File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow());
|
||||
if (file != null) {
|
||||
useLoadFileService(fileReader, file);
|
||||
useLoadFileService(fileReader, file, event -> runLater(() -> {
|
||||
resetContent();
|
||||
fileChanged.setValue(false);
|
||||
}));
|
||||
return file;
|
||||
} else {
|
||||
return initChildFile;
|
||||
@@ -462,14 +542,11 @@ public class SmartCSVController extends FXMLController {
|
||||
return file;
|
||||
}
|
||||
|
||||
private void useLoadFileService(FileReader fileReader, File file) {
|
||||
private void useLoadFileService(FileReader fileReader, File file, EventHandler<WorkerStateEvent> value) {
|
||||
loadFileService.setFile(file);
|
||||
loadFileService.setFileReader(fileReader);
|
||||
loadFileService.restart();
|
||||
loadFileService.setOnSucceeded(event -> runLater(() -> {
|
||||
resetContent();
|
||||
fileChanged.setValue(false);
|
||||
}));
|
||||
loadFileService.setOnSucceeded(value);
|
||||
}
|
||||
|
||||
private void useSaveFileService(FileWriter writer, File file) {
|
||||
@@ -488,7 +565,9 @@ public class SmartCSVController extends FXMLController {
|
||||
private void resetContent() {
|
||||
model = csvLoader.getData();
|
||||
if (model != null) {
|
||||
model.setValidator(validationLoader.getValidator());
|
||||
model.getValidationError().addListener(weakErrorListListener);
|
||||
model.setValidationConfiguration(validationLoader.getValidationConfiguration());
|
||||
validationEditorController.setValidationConfiguration(validationLoader.getValidationConfiguration());
|
||||
tableView = new TableView<>();
|
||||
|
||||
bindMenuItemsToTableSelection(deleteRowMenuItem);
|
||||
@@ -520,6 +599,11 @@ public class SmartCSVController extends FXMLController {
|
||||
column.setCellValueFactory(new ObservableMapValueFactory(header));
|
||||
column.setCellFactory(cellFactory);
|
||||
column.setEditable(true);
|
||||
column.setSortable(false);
|
||||
|
||||
ContextMenu contextMenu = contextMenuForColumn(header);
|
||||
column.setContextMenu(contextMenu);
|
||||
|
||||
column.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<CSVRow, CSVValue>>() {
|
||||
@Override
|
||||
public void handle(TableColumn.CellEditEvent<CSVRow, CSVValue> event) {
|
||||
@@ -535,6 +619,15 @@ public class SmartCSVController extends FXMLController {
|
||||
tableView.getColumns().add(column);
|
||||
}
|
||||
|
||||
private ContextMenu contextMenuForColumn(String header) {
|
||||
ContextMenu contextMenu = new ContextMenu();
|
||||
MenuItem editColumnRulesMenuItem = new MenuItem(resourceBundle.getString("context.menu.edit.column.rules"));
|
||||
bindMenuItemsToFileExistence(currentConfigFile, editColumnRulesMenuItem);
|
||||
editColumnRulesMenuItem.setOnAction(e -> showValidationEditor(header));
|
||||
contextMenu.getItems().addAll(editColumnRulesMenuItem);
|
||||
return contextMenu;
|
||||
}
|
||||
|
||||
private void scrollToError(ValidationError entry) {
|
||||
if (entry != null) {
|
||||
if (entry.getLineNumber() != null) {
|
||||
|
||||
@@ -26,12 +26,8 @@
|
||||
|
||||
package ninja.javafx.smartcsv.fx.preferences;
|
||||
|
||||
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.fxml.FXML;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ComboBox;
|
||||
|
||||
@@ -28,6 +28,7 @@ package ninja.javafx.smartcsv.fx.table.model;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import ninja.javafx.smartcsv.validation.ValidationConfiguration;
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
import ninja.javafx.smartcsv.validation.Validator;
|
||||
|
||||
@@ -43,11 +44,11 @@ public class CSVModel {
|
||||
private ObservableList<ValidationError> validationError = FXCollections.observableArrayList();
|
||||
|
||||
/**
|
||||
* sets the validator for the data revalidates
|
||||
* @param validator the validator for this data
|
||||
* sets the validator configuration for the data revalidates
|
||||
* @param validationConfiguration the validator configuration for this data
|
||||
*/
|
||||
public void setValidator(Validator validator) {
|
||||
this.validator = validator;
|
||||
public void setValidationConfiguration(ValidationConfiguration validationConfiguration) {
|
||||
this.validator = new Validator(validationConfiguration);
|
||||
revalidate();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.fx.validation;
|
||||
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.*;
|
||||
import ninja.javafx.smartcsv.fx.FXMLController;
|
||||
import ninja.javafx.smartcsv.validation.ValidationConfiguration;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
/**
|
||||
* controller for editing column validations
|
||||
*/
|
||||
@Component
|
||||
public class ValidationEditorController extends FXMLController {
|
||||
|
||||
private StringProperty selectedColumn = new SimpleStringProperty();
|
||||
private ValidationConfiguration validationConfiguration;
|
||||
|
||||
@FXML
|
||||
private CheckBox notEmptyRuleCheckBox;
|
||||
|
||||
@FXML
|
||||
private CheckBox integerRuleCheckBox;
|
||||
|
||||
@FXML
|
||||
private CheckBox doublerRuleCheckBox;
|
||||
|
||||
@FXML
|
||||
private CheckBox alphanumericRuleCheckBox;
|
||||
|
||||
@FXML
|
||||
private Spinner<Integer> minLengthSpinner;
|
||||
|
||||
@FXML
|
||||
private Spinner<Integer> maxLengthSpinner;
|
||||
|
||||
@FXML
|
||||
private TextField dateformatRuleTextField;
|
||||
|
||||
@FXML
|
||||
private TextField regexpRuleTextField;
|
||||
|
||||
@FXML
|
||||
private TextField valueOfRuleTextField;
|
||||
|
||||
@FXML
|
||||
private TextArea groovyRuleTextArea;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableNotEmptyRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableIntegerRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableDoubleRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableAlphanumericRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableMinLengthRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableMaxLengthRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableDateRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableRegexpRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableValueOfRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableGroovyRule;
|
||||
|
||||
|
||||
@Value("${fxml.smartcvs.validation.editor.view}")
|
||||
@Override
|
||||
public void setFxmlFilePath(String filePath) {
|
||||
this.fxmlFilePath = filePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
|
||||
minLengthSpinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(0, Integer.MAX_VALUE, 0));
|
||||
maxLengthSpinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(0, Integer.MAX_VALUE, 0));
|
||||
|
||||
initCheckBox(notEmptyRuleCheckBox, enableNotEmptyRule);
|
||||
initCheckBox(integerRuleCheckBox, enableIntegerRule);
|
||||
initCheckBox(doublerRuleCheckBox, enableDoubleRule);
|
||||
initCheckBox(alphanumericRuleCheckBox, enableAlphanumericRule);
|
||||
initSpinner(minLengthSpinner, enableMinLengthRule);
|
||||
initSpinner(maxLengthSpinner, enableMaxLengthRule);
|
||||
initTextInputControl(dateformatRuleTextField, enableDateRule);
|
||||
initTextInputControl(regexpRuleTextField, enableRegexpRule);
|
||||
initTextInputControl(valueOfRuleTextField, enableValueOfRule);
|
||||
initTextInputControl(groovyRuleTextArea, enableGroovyRule);
|
||||
|
||||
selectedColumn.addListener(observable -> {
|
||||
updateForm();
|
||||
});
|
||||
}
|
||||
|
||||
public String getSelectedColumn() {
|
||||
return selectedColumn.get();
|
||||
}
|
||||
|
||||
public StringProperty selectedColumnProperty() {
|
||||
return selectedColumn;
|
||||
}
|
||||
|
||||
public void setSelectedColumn(String selectedColumn) {
|
||||
this.selectedColumn.set(selectedColumn);
|
||||
}
|
||||
|
||||
public void setValidationConfiguration(ValidationConfiguration validationConfiguration) {
|
||||
this.validationConfiguration = validationConfiguration;
|
||||
}
|
||||
|
||||
public void updateConfiguration() {
|
||||
|
||||
if (enableIntegerRule.isSelected()) {
|
||||
validationConfiguration.setIntegerRuleFor(selectedColumn.getValue(), integerRuleCheckBox.isSelected());
|
||||
} else {
|
||||
validationConfiguration.setIntegerRuleFor(selectedColumn.getValue(), null);
|
||||
}
|
||||
|
||||
if (enableNotEmptyRule.isSelected()) {
|
||||
validationConfiguration.setNotEmptyRuleFor(selectedColumn.getValue(), notEmptyRuleCheckBox.isSelected());
|
||||
} else {
|
||||
validationConfiguration.setNotEmptyRuleFor(selectedColumn.getValue(), null);
|
||||
}
|
||||
|
||||
if (enableDoubleRule.isSelected()) {
|
||||
validationConfiguration.setDoubleRuleFor(selectedColumn.getValue(), doublerRuleCheckBox.isSelected());
|
||||
} else {
|
||||
validationConfiguration.setDoubleRuleFor(selectedColumn.getValue(), null);
|
||||
}
|
||||
|
||||
if (enableAlphanumericRule.isSelected()) {
|
||||
validationConfiguration.setAlphanumericRuleFor(selectedColumn.getValue(), alphanumericRuleCheckBox.isSelected());
|
||||
} else {
|
||||
validationConfiguration.setAlphanumericRuleFor(selectedColumn.getValue(), null);
|
||||
}
|
||||
|
||||
if (enableDateRule.isSelected()) {
|
||||
validationConfiguration.setDateRuleFor(selectedColumn.getValue(), dateformatRuleTextField.getText());
|
||||
} else {
|
||||
validationConfiguration.setDateRuleFor(selectedColumn.getValue(), null);
|
||||
}
|
||||
|
||||
if (enableGroovyRule.isSelected()) {
|
||||
validationConfiguration.setGroovyRuleFor(selectedColumn.getValue(), groovyRuleTextArea.getText());
|
||||
} else {
|
||||
validationConfiguration.setGroovyRuleFor(selectedColumn.getValue(), null);
|
||||
}
|
||||
|
||||
if (enableMinLengthRule.isSelected()) {
|
||||
validationConfiguration.setMinLengthRuleFor(selectedColumn.getValue(), minLengthSpinner.getValue());
|
||||
} else {
|
||||
validationConfiguration.setMinLengthRuleFor(selectedColumn.getValue(), null);
|
||||
}
|
||||
|
||||
if (enableMaxLengthRule.isSelected()) {
|
||||
validationConfiguration.setMaxLengthRuleFor(selectedColumn.getValue(), maxLengthSpinner.getValue());
|
||||
} else {
|
||||
validationConfiguration.setMaxLengthRuleFor(selectedColumn.getValue(), null);
|
||||
}
|
||||
|
||||
if (enableRegexpRule.isSelected()) {
|
||||
validationConfiguration.setRegexpRuleFor(selectedColumn.getValue(), regexpRuleTextField.getText());
|
||||
} else {
|
||||
validationConfiguration.setRegexpRuleFor(selectedColumn.getValue(), null);
|
||||
}
|
||||
|
||||
if (enableValueOfRule.isSelected()) {
|
||||
validationConfiguration.setValueOfRuleFor(selectedColumn.getValue(), asList(valueOfRuleTextField.getText().split(", ")));
|
||||
} else {
|
||||
validationConfiguration.setValueOfRuleFor(selectedColumn.getValue(), null);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateForm() {
|
||||
|
||||
updateCheckBox(
|
||||
notEmptyRuleCheckBox,
|
||||
validationConfiguration.getNotEmptyRuleFor(getSelectedColumn()),
|
||||
enableNotEmptyRule
|
||||
);
|
||||
|
||||
updateCheckBox(
|
||||
integerRuleCheckBox,
|
||||
validationConfiguration.getIntegerRuleFor(getSelectedColumn()),
|
||||
enableIntegerRule
|
||||
);
|
||||
|
||||
updateCheckBox(
|
||||
doublerRuleCheckBox,
|
||||
validationConfiguration.getDoubleRuleFor(getSelectedColumn()),
|
||||
enableDoubleRule
|
||||
);
|
||||
|
||||
updateCheckBox(
|
||||
alphanumericRuleCheckBox,
|
||||
validationConfiguration.getAlphanumericRuleFor(getSelectedColumn()),
|
||||
enableAlphanumericRule
|
||||
);
|
||||
|
||||
updateSpinner(
|
||||
minLengthSpinner,
|
||||
validationConfiguration.getMinLengthRuleFor(getSelectedColumn()),
|
||||
enableMinLengthRule
|
||||
);
|
||||
|
||||
updateSpinner(
|
||||
maxLengthSpinner,
|
||||
validationConfiguration.getMaxLengthRuleFor(getSelectedColumn()),
|
||||
enableMaxLengthRule
|
||||
);
|
||||
|
||||
updateTextInputControl(
|
||||
dateformatRuleTextField,
|
||||
validationConfiguration.getDateRuleFor(getSelectedColumn()),
|
||||
enableDateRule
|
||||
);
|
||||
|
||||
updateTextInputControl(
|
||||
regexpRuleTextField,
|
||||
validationConfiguration.getRegexpRuleFor(getSelectedColumn()),
|
||||
enableRegexpRule
|
||||
);
|
||||
|
||||
updateTextInputControl(
|
||||
valueOfRuleTextField,
|
||||
validationConfiguration.getValueOfRuleFor(getSelectedColumn()),
|
||||
enableValueOfRule
|
||||
);
|
||||
|
||||
updateTextInputControl(
|
||||
groovyRuleTextArea,
|
||||
validationConfiguration.getGroovyRuleFor(getSelectedColumn()),
|
||||
enableGroovyRule
|
||||
);
|
||||
}
|
||||
|
||||
private void updateCheckBox(CheckBox rule, Boolean value, CheckBox ruleEnabled) {
|
||||
if (value == null) {
|
||||
ruleEnabled.setSelected(false);
|
||||
} else {
|
||||
rule.setSelected(value);
|
||||
ruleEnabled.setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSpinner(Spinner rule, Integer value, CheckBox ruleEnabled) {
|
||||
if (value == null) {
|
||||
ruleEnabled.setSelected(false);
|
||||
} else {
|
||||
ruleEnabled.setSelected(true);
|
||||
rule.getValueFactory().setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTextInputControl(TextInputControl rule, String value, CheckBox ruleEnabled) {
|
||||
if (value == null) {
|
||||
ruleEnabled.setSelected(false);
|
||||
} else {
|
||||
ruleEnabled.setSelected(true);
|
||||
rule.setText(value);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTextInputControl(TextInputControl rule, List<String> values, CheckBox ruleEnabled) {
|
||||
if (values == null || values.isEmpty()) {
|
||||
ruleEnabled.setSelected(false);
|
||||
} else {
|
||||
ruleEnabled.setSelected(true);
|
||||
rule.setText(values.stream().collect(joining(", ")));
|
||||
}
|
||||
}
|
||||
|
||||
private void initCheckBox(CheckBox rule, CheckBox ruleEnabled) {
|
||||
rule.disableProperty().bind(ruleEnabled.selectedProperty().not());
|
||||
ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
rule.setSelected(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initSpinner(Spinner rule, CheckBox ruleEnabled) {
|
||||
rule.disableProperty().bind(ruleEnabled.selectedProperty().not());
|
||||
ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
rule.getValueFactory().setValue(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initTextInputControl(TextInputControl rule, CheckBox ruleEnabled) {
|
||||
rule.disableProperty().bind(ruleEnabled.selectedProperty().not());
|
||||
ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
rule.setText("");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,8 +26,7 @@
|
||||
|
||||
package ninja.javafx.smartcsv.preferences;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import ninja.javafx.smartcsv.FileReader;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.supercsv.prefs.CsvPreference;
|
||||
@@ -35,6 +34,8 @@ import org.supercsv.quote.AlwaysQuoteMode;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static ninja.javafx.smartcsv.preferences.QuoteModeHelper.getQuoteMode;
|
||||
|
||||
@@ -44,7 +45,7 @@ import static ninja.javafx.smartcsv.preferences.QuoteModeHelper.getQuoteMode;
|
||||
@Service
|
||||
public class PreferencesFileReader implements FileReader {
|
||||
|
||||
private Config config;
|
||||
private Map config;
|
||||
private CsvPreference csvPreference;
|
||||
|
||||
public PreferencesFileReader() {
|
||||
@@ -55,15 +56,15 @@ public class PreferencesFileReader implements FileReader {
|
||||
|
||||
@Override
|
||||
public void read(File filename) throws IOException {
|
||||
config = ConfigFactory.parseFile(filename);
|
||||
config = new GsonBuilder().create().fromJson(new java.io.FileReader(filename), HashMap.class);
|
||||
|
||||
if (config != null) {
|
||||
char quoteChar = config.getString("quoteChar").charAt(0);
|
||||
char delimiterChar = config.getString("delimiterChar").charAt(0);
|
||||
String endOfLineSymbols = config.getString("endOfLineSymbols");
|
||||
boolean surroundingSpacesNeedQuotes = config.getBoolean("surroundingSpacesNeedQuotes");
|
||||
boolean ignoreEmptyLines = config.getBoolean("ignoreEmptyLines");
|
||||
String quoteMode = config.getString("quoteMode");
|
||||
char quoteChar = config.get("quoteChar").toString().charAt(0);
|
||||
char delimiterChar = config.get("delimiterChar").toString().charAt(0);
|
||||
String endOfLineSymbols = config.get("endOfLineSymbols").toString();
|
||||
boolean surroundingSpacesNeedQuotes = (Boolean)config.get("surroundingSpacesNeedQuotes");
|
||||
boolean ignoreEmptyLines = (Boolean)config.get("ignoreEmptyLines");
|
||||
String quoteMode = config.get("quoteMode").toString();
|
||||
|
||||
csvPreference = new CsvPreference.Builder(quoteChar, delimiterChar, endOfLineSymbols)
|
||||
.useQuoteMode(getQuoteMode(quoteMode))
|
||||
|
||||
@@ -26,9 +26,8 @@
|
||||
|
||||
package ninja.javafx.smartcsv.preferences;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import com.typesafe.config.ConfigRenderOptions;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import ninja.javafx.smartcsv.FileWriter;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.supercsv.prefs.CsvPreference;
|
||||
@@ -60,8 +59,8 @@ public class PreferencesFileWriter implements FileWriter {
|
||||
preferences.put("ignoreEmptyLines", csvPreference.isIgnoreEmptyLines());
|
||||
preferences.put("quoteMode", QuoteModeHelper.getQuoteModeName(csvPreference.getQuoteMode()));
|
||||
|
||||
Config config = ConfigFactory.parseMap(preferences);
|
||||
Files.write(file.toPath(), config.root().render(ConfigRenderOptions.concise()).getBytes());
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
Files.write(file.toPath(), gson.toJson(preferences).getBytes());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* header configuration for the validation
|
||||
*/
|
||||
public class HeaderConfiguration {
|
||||
|
||||
@SerializedName("list")
|
||||
private String[] names ;
|
||||
|
||||
public String[] getNames() {
|
||||
return names;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* validation configuration
|
||||
*/
|
||||
public class ValidationConfiguration {
|
||||
|
||||
@SerializedName("headers")
|
||||
private HeaderConfiguration headerConfiguration = new HeaderConfiguration();
|
||||
|
||||
@SerializedName("columns")
|
||||
private Map<String, Map<String, Object>> columnConfigurations = new HashMap<>();
|
||||
|
||||
public String[] headerNames() {
|
||||
if (noHeader()) return null;
|
||||
return headerConfiguration.getNames();
|
||||
}
|
||||
|
||||
public Boolean getIntegerRuleFor(String column) {
|
||||
return (Boolean)getValue(column, "integer");
|
||||
}
|
||||
|
||||
public Boolean getDoubleRuleFor(String column) {
|
||||
return (Boolean)getValue(column, "double");
|
||||
}
|
||||
|
||||
public Boolean getNotEmptyRuleFor(String column) {
|
||||
return (Boolean)getValue(column, "not empty");
|
||||
}
|
||||
|
||||
public Integer getMinLengthRuleFor(String column) {
|
||||
return doubleToInteger((Double)getValue(column, "minlength"));
|
||||
}
|
||||
|
||||
public Integer getMaxLengthRuleFor(String column) {
|
||||
if (noRulesFor(column)) return null;
|
||||
return doubleToInteger((Double)getValue(column, "maxlength"));
|
||||
}
|
||||
|
||||
public String getDateRuleFor(String column) {
|
||||
if (noRulesFor(column)) return null;
|
||||
return (String)getValue(column, "date");
|
||||
}
|
||||
|
||||
public Boolean getAlphanumericRuleFor(String column) {
|
||||
if (noRulesFor(column)) return null;
|
||||
return (Boolean)getValue(column, "alphanumeric");
|
||||
}
|
||||
|
||||
public String getRegexpRuleFor(String column) {
|
||||
if (noRulesFor(column)) return null;
|
||||
return (String)getValue(column, "regexp");
|
||||
}
|
||||
|
||||
public List<String> getValueOfRuleFor(String column) {
|
||||
if (noRulesFor(column)) return null;
|
||||
return (List<String>)getValue(column, "value of");
|
||||
}
|
||||
|
||||
public String getGroovyRuleFor(String column) {
|
||||
if (noRulesFor(column)) return null;
|
||||
return (String)getValue(column, "groovy");
|
||||
}
|
||||
|
||||
public void setIntegerRuleFor(String column, Boolean value) {
|
||||
setValue(column, value, "integer");
|
||||
}
|
||||
|
||||
public void setDoubleRuleFor(String column, Boolean value) {
|
||||
setValue(column, value, "double");
|
||||
}
|
||||
|
||||
public void setNotEmptyRuleFor(String column, Boolean value) {
|
||||
setValue(column, value, "not empty");
|
||||
}
|
||||
|
||||
public void setMinLengthRuleFor(String column, Integer value) {
|
||||
setValue(column, value == null ? null : value.doubleValue(), "minlength");
|
||||
}
|
||||
|
||||
public void setMaxLengthRuleFor(String column, Integer value) {
|
||||
setValue(column, value == null ? null : value.doubleValue(), "maxlength");
|
||||
}
|
||||
|
||||
public void setDateRuleFor(String column, String value) {
|
||||
setValue(column, value, "date");
|
||||
}
|
||||
|
||||
public void setAlphanumericRuleFor(String column, Boolean value) {
|
||||
setValue(column, value, "alphanumeric");
|
||||
}
|
||||
|
||||
public void setRegexpRuleFor(String column, String value) {
|
||||
setValue(column, value, "regexp");
|
||||
}
|
||||
|
||||
public void setValueOfRuleFor(String column, List<String> value) {
|
||||
setValue(column, value, "value of");
|
||||
}
|
||||
|
||||
public void setGroovyRuleFor(String column, String value) {
|
||||
setValue(column, value, "groovy");
|
||||
}
|
||||
|
||||
private void setValue(String column, Object value, String key) {
|
||||
if (!columnConfigurations.containsKey(column)) {
|
||||
columnConfigurations.put(column, new HashMap<>());
|
||||
}
|
||||
|
||||
if (value == null && columnConfigurations.get(column).containsKey(key)) {
|
||||
columnConfigurations.get(column).remove(key);
|
||||
} else {
|
||||
columnConfigurations.get(column).put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
private Object getValue(String column, String key) {
|
||||
if (noRulesFor(column)) return null;
|
||||
return columnConfigurations.get(column).get(key);
|
||||
}
|
||||
|
||||
private boolean noHeader() {
|
||||
return headerConfiguration == null;
|
||||
}
|
||||
|
||||
private boolean noRulesFor(String column) {
|
||||
return columnConfigurations == null || columnConfigurations.get(column) == null;
|
||||
}
|
||||
|
||||
private Integer doubleToInteger(Double value) {
|
||||
if (value == null) return null;
|
||||
return (int)Math.round(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,8 +26,7 @@
|
||||
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import ninja.javafx.smartcsv.FileReader;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -40,14 +39,14 @@ import java.io.IOException;
|
||||
@Service
|
||||
public class ValidationFileReader implements FileReader {
|
||||
|
||||
private Config config;
|
||||
private ValidationConfiguration config;
|
||||
|
||||
@Override
|
||||
public void read(File file) throws IOException {
|
||||
config = ConfigFactory.parseFile(file);
|
||||
config = new GsonBuilder().create().fromJson(new java.io.FileReader(file), ValidationConfiguration.class);
|
||||
}
|
||||
|
||||
public Validator getValidator() {
|
||||
return new Validator(config);
|
||||
public ValidationConfiguration getValidationConfiguration() {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import ninja.javafx.smartcsv.FileWriter;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
/**
|
||||
* file writer for the validation configuration
|
||||
*/
|
||||
@Service
|
||||
public class ValidationFileWriter implements FileWriter {
|
||||
|
||||
private ValidationConfiguration validationConfiguration;
|
||||
|
||||
public void setValidationConfiguration(ValidationConfiguration validationConfiguration) {
|
||||
this.validationConfiguration = validationConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(File file) throws IOException {
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
Files.write(file.toPath(), gson.toJson(validationConfiguration).getBytes());
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import groovy.lang.Binding;
|
||||
import groovy.lang.GroovyShell;
|
||||
import groovy.lang.Script;
|
||||
@@ -49,7 +48,7 @@ public class Validator {
|
||||
// member variables
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private Config validationConfig;
|
||||
private ValidationConfiguration validationConfig;
|
||||
private GroovyShell shell = new GroovyShell();
|
||||
private Map<String, Script> scriptCache = new HashMap<>();
|
||||
|
||||
@@ -62,7 +61,7 @@ public class Validator {
|
||||
* JSON configuration for this validator
|
||||
* @param validationConfig
|
||||
*/
|
||||
public Validator(Config validationConfig) {
|
||||
public Validator(ValidationConfiguration validationConfig) {
|
||||
this.validationConfig = validationConfig;
|
||||
}
|
||||
|
||||
@@ -80,29 +79,23 @@ public class Validator {
|
||||
public ValidationError isValid(String column, String value, Integer lineNumber) {
|
||||
ValidationError result = null;
|
||||
if (validationConfig != null) {
|
||||
Config columnSectionConfig = getColumnSectionConfig();
|
||||
if (columnSectionConfig != null) {
|
||||
Config columnConfig = getColumnConfig(columnSectionConfig, column);
|
||||
if (columnConfig != null) {
|
||||
|
||||
ValidationError error = ValidationError.withLineNumber(lineNumber);
|
||||
checkBlankOrNull(columnConfig, value, error);
|
||||
if (value != null && !value.isEmpty()) {
|
||||
checkRegularExpression(columnConfig, value, error);
|
||||
checkAlphaNumeric(columnConfig, value, error);
|
||||
checkDate(columnConfig, value, error);
|
||||
checkMaxLength(columnConfig, value, error);
|
||||
checkMinLength(columnConfig, value, error);
|
||||
checkInteger(columnConfig, value, error);
|
||||
checkGroovy(column, columnConfig, value, error);
|
||||
checkValueOf(columnConfig, value, error);
|
||||
checkDouble(columnConfig, value, error);
|
||||
}
|
||||
ValidationError error = ValidationError.withLineNumber(lineNumber);
|
||||
checkBlankOrNull(column, value, error);
|
||||
if (value != null && !value.isEmpty()) {
|
||||
checkRegularExpression(column, value, error);
|
||||
checkAlphaNumeric(column, value, error);
|
||||
checkDate(column, value, error);
|
||||
checkMaxLength(column, value, error);
|
||||
checkMinLength(column, value, error);
|
||||
checkInteger(column, value, error);
|
||||
checkGroovy(column, value, error);
|
||||
checkValueOf(column, value, error);
|
||||
checkDouble(column, value, error);
|
||||
}
|
||||
|
||||
if (!error.isEmpty()) {
|
||||
result = error;
|
||||
}
|
||||
}
|
||||
if (!error.isEmpty()) {
|
||||
result = error;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -113,8 +106,8 @@ public class Validator {
|
||||
// private methods
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void checkGroovy(String column, Config columnConfig, String value, ValidationError error) {
|
||||
String groovyScript = getString(columnConfig, "groovy");
|
||||
private void checkGroovy(String column, String value, ValidationError error) {
|
||||
String groovyScript = validationConfig.getGroovyRuleFor(column);
|
||||
if (groovyScript != null) {
|
||||
|
||||
Script script = scriptCache.get(column);
|
||||
@@ -149,43 +142,42 @@ public class Validator {
|
||||
return groovyResult.equals(true) || groovyResult.toString().trim().toLowerCase().equals("true");
|
||||
}
|
||||
|
||||
private void checkValueOf(Config columnConfig, String value, ValidationError error) {
|
||||
List<String> stringList = getStringList(columnConfig, "value of");
|
||||
if (stringList != null) {
|
||||
if (!stringList.contains(value)) {
|
||||
String commaSeparated = stringList.stream().collect(joining(", "));
|
||||
private void checkValueOf(String column, String value, ValidationError error) {
|
||||
List<String> values = validationConfig.getValueOfRuleFor(column);
|
||||
if (values != null) {
|
||||
if (!values.contains(value)) {
|
||||
String commaSeparated = values.stream().collect(joining(", "));
|
||||
error.add("validation.message.value.of", value, commaSeparated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkBlankOrNull(Config columnConfig, String value, ValidationError error) {
|
||||
if (getBoolean(columnConfig, "not empty")) {
|
||||
private void checkBlankOrNull(String column, String value, ValidationError error) {
|
||||
if (validationConfig.getNotEmptyRuleFor(column) != null && validationConfig.getNotEmptyRuleFor(column)) {
|
||||
if (isBlankOrNull(value)) {
|
||||
error.add("validation.message.not.empty");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkInteger(Config columnConfig, String value, ValidationError error) {
|
||||
if (getBoolean(columnConfig, "integer")) {
|
||||
private void checkInteger(String column, String value, ValidationError error) {
|
||||
if (validationConfig.getIntegerRuleFor(column) != null && validationConfig.getIntegerRuleFor(column)) {
|
||||
if (!isInt(value)) {
|
||||
error.add("validation.message.integer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDouble(Config columnConfig, String value, ValidationError error) {
|
||||
if (getBoolean(columnConfig, "double")) {
|
||||
private void checkDouble(String column, String value, ValidationError error) {
|
||||
if (validationConfig.getDoubleRuleFor(column) != null && validationConfig.getDoubleRuleFor(column)) {
|
||||
if (!isDouble(value)) {
|
||||
error.add("validation.message.double");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void checkMinLength(Config columnConfig, String value, ValidationError error) {
|
||||
Integer minLength = getInteger(columnConfig, "minlength");
|
||||
private void checkMinLength(String column, String value, ValidationError error) {
|
||||
Integer minLength = validationConfig.getMinLengthRuleFor(column);
|
||||
if (minLength != null) {
|
||||
if (!minLength(value, minLength)) {
|
||||
error.add("validation.message.min.length", minLength.toString());
|
||||
@@ -193,8 +185,8 @@ public class Validator {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkMaxLength(Config columnConfig, String value, ValidationError error) {
|
||||
Integer maxLength = getInteger(columnConfig, "maxlength");
|
||||
private void checkMaxLength(String column, String value, ValidationError error) {
|
||||
Integer maxLength = validationConfig.getMaxLengthRuleFor(column);
|
||||
if (maxLength != null) {
|
||||
if (!maxLength(value, maxLength)) {
|
||||
error.add("validation.message.max.length", maxLength.toString());
|
||||
@@ -202,8 +194,8 @@ public class Validator {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDate(Config columnConfig, String value, ValidationError error) {
|
||||
String dateformat = getString(columnConfig, "date");
|
||||
private void checkDate(String column, String value, ValidationError error) {
|
||||
String dateformat = validationConfig.getDateRuleFor(column);
|
||||
if (dateformat != null && !dateformat.trim().isEmpty()) {
|
||||
if (!isDate(value, dateformat, true)) {
|
||||
error.add("validation.message.date.format", dateformat);
|
||||
@@ -211,16 +203,16 @@ public class Validator {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAlphaNumeric(Config columnConfig, String value, ValidationError error) {
|
||||
if (getBoolean(columnConfig, "alphanumeric")) {
|
||||
private void checkAlphaNumeric(String column, String value, ValidationError error) {
|
||||
if (validationConfig.getAlphanumericRuleFor(column) != null && validationConfig.getAlphanumericRuleFor(column)) {
|
||||
if (!matchRegexp(value, "[0-9a-zA-Z]*")) {
|
||||
error.add("validation.message.alphanumeric");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRegularExpression(Config columnConfig, String value, ValidationError error) {
|
||||
String regexp = getString(columnConfig, "regexp");
|
||||
private void checkRegularExpression(String column, String value, ValidationError error) {
|
||||
String regexp = validationConfig.getRegexpRuleFor(column);
|
||||
if (regexp != null && !regexp.trim().isEmpty()) {
|
||||
if (!matchRegexp(value, regexp)) {
|
||||
error.add("validation.message.regexp", regexp);
|
||||
@@ -228,60 +220,31 @@ public class Validator {
|
||||
}
|
||||
}
|
||||
|
||||
private Config getColumnSectionConfig() {
|
||||
return validationConfig.hasPath("columns") ? validationConfig.getConfig("columns") : null;
|
||||
}
|
||||
|
||||
private Config getColumnConfig(Config columnSectionConfig, String column) {
|
||||
return columnSectionConfig.hasPath(column) ? columnSectionConfig.getConfig(column) : null;
|
||||
}
|
||||
|
||||
|
||||
private String getString(Config columnConfig, String path) {
|
||||
return columnConfig.hasPath(path) ? columnConfig.getString(path) : null;
|
||||
}
|
||||
|
||||
private Integer getInteger(Config columnConfig, String path) {
|
||||
return columnConfig.hasPath(path) ? columnConfig.getInt(path) : null;
|
||||
}
|
||||
|
||||
private boolean getBoolean(Config columnConfig, String path) {
|
||||
return columnConfig.hasPath(path) && columnConfig.getBoolean(path);
|
||||
}
|
||||
|
||||
private List<String> getStringList(Config columnConfig, String path) {
|
||||
return columnConfig.hasPath(path) ? columnConfig.getStringList(path) : null;
|
||||
}
|
||||
|
||||
public ValidationError isHeaderValid(String[] headerNames) {
|
||||
ValidationError result = null;
|
||||
if (validationConfig != null) {
|
||||
if (validationConfig.hasPath("headers")) {
|
||||
Config headerSectionConfig = validationConfig.getConfig("headers");
|
||||
List<String> headerConfig = getStringList(headerSectionConfig, "list");
|
||||
if (headerConfig != null) {
|
||||
if (headerNames.length != headerConfig.size()) {
|
||||
result = ValidationError.withoutLineNumber().add("validation.message.header.length",
|
||||
Integer.toString(headerNames.length),
|
||||
Integer.toString(headerConfig.size()));
|
||||
return result;
|
||||
}
|
||||
String[] headerNamesConfig = validationConfig.headerNames();
|
||||
if (headerNamesConfig != null) {
|
||||
if (headerNames.length != headerNamesConfig.length) {
|
||||
result = ValidationError.withoutLineNumber().add("validation.message.header.length",
|
||||
Integer.toString(headerNames.length),
|
||||
Integer.toString(headerNamesConfig.length));
|
||||
return result;
|
||||
}
|
||||
|
||||
ValidationError error = ValidationError.withoutLineNumber();
|
||||
ValidationError error = ValidationError.withoutLineNumber();
|
||||
|
||||
for(int i=0; i<headerConfig.size(); i++) {
|
||||
String header = headerConfig.get(i);
|
||||
if (!header.equals(headerNames[i])) {
|
||||
error.add("validation.message.header.match",
|
||||
Integer.toString(i),
|
||||
header,
|
||||
headerNames[i]);
|
||||
}
|
||||
}
|
||||
if (!error.isEmpty()) {
|
||||
result = error;
|
||||
for(int i=0; i<headerNamesConfig.length; i++) {
|
||||
if (!headerNamesConfig[i].equals(headerNames[i])) {
|
||||
error.add("validation.message.header.match",
|
||||
Integer.toString(i),
|
||||
headerNamesConfig[i],
|
||||
headerNames[i]);
|
||||
}
|
||||
}
|
||||
if (!error.isEmpty()) {
|
||||
result = error;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="https://spring.io/" GridPane.columnIndex="1" GridPane.rowIndex="3" />
|
||||
<Label text="supercsv" GridPane.rowIndex="4" />
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="http://super-csv.github.io/super-csv/" GridPane.columnIndex="1" GridPane.rowIndex="4" />
|
||||
<Label text="config" GridPane.rowIndex="5" />
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="https://github.com/typesafehub/config" GridPane.columnIndex="1" GridPane.rowIndex="5" />
|
||||
<Label text="Gson" GridPane.rowIndex="5" />
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="https://github.com/google/gson/" GridPane.columnIndex="1" GridPane.rowIndex="5" />
|
||||
<Label text="commons-validator" GridPane.rowIndex="6" />
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="https://commons.apache.org/proper/commons-validator/" GridPane.columnIndex="1" GridPane.rowIndex="6" />
|
||||
<Label text="fontawesomefx" GridPane.rowIndex="7" />
|
||||
|
||||
@@ -5,6 +5,7 @@ application.version = 0.3
|
||||
fxml.smartcvs.view = /ninja/javafx/smartcsv/fx/smartcsv.fxml
|
||||
fxml.smartcvs.about.view = /ninja/javafx/smartcsv/fx/about/about.fxml
|
||||
fxml.smartcvs.preferences.view = /ninja/javafx/smartcsv/fx/preferences/preferences.fxml
|
||||
fxml.smartcvs.validation.editor.view = /ninja/javafx/smartcsv/fx/validation/validationEditor.fxml
|
||||
|
||||
# resources
|
||||
resource.main = ninja.javafx.smartcsv.fx.smartcsv
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
<?import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView?>
|
||||
<?import ninja.javafx.smartcsv.fx.list.ErrorSideBar?>
|
||||
<?import de.jensd.fx.glyphs.GlyphsStack?>
|
||||
<BorderPane fx:id="applicationPane" maxHeight="-Infinity" maxWidth="1000.0" minHeight="700.0" minWidth="-Infinity" prefHeight="700.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<top>
|
||||
<VBox id="background" prefWidth="100.0" BorderPane.alignment="CENTER">
|
||||
@@ -38,12 +39,6 @@
|
||||
<FontAwesomeIconView styleClass="open-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
<MenuItem mnemonicParsing="false" onAction="#openConfig" text="%menu.open.config">
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="config-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem fx:id="saveMenuItem" disable="true" mnemonicParsing="false" onAction="#saveCsv" text="%menu.save">
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="save-icon" />
|
||||
@@ -54,6 +49,34 @@
|
||||
<FontAwesomeIconView styleClass="save-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem fx:id="loadConfigMenuItem" disable="true" mnemonicParsing="false" onAction="#openConfig" text="%menu.open.config">
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="config-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
<MenuItem fx:id="saveConfigMenuItem" disable="true" mnemonicParsing="false" onAction="#saveConfig" text="%menu.save.config">
|
||||
<graphic>
|
||||
<GlyphsStack>
|
||||
<children>
|
||||
<FontAwesomeIconView styleClass="save-icon" style="-fx-opacity: 0.7;" />
|
||||
<FontAwesomeIconView styleClass="config-icon" />
|
||||
</children>
|
||||
</GlyphsStack>
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
<MenuItem fx:id="saveAsConfigMenuItem" disable="true" mnemonicParsing="false" onAction="#saveAsConfig" text="%menu.save.as.config">
|
||||
<graphic>
|
||||
<GlyphsStack>
|
||||
<children>
|
||||
<FontAwesomeIconView styleClass="save-icon" style="-fx-opacity: 0.7;" />
|
||||
<FontAwesomeIconView styleClass="config-icon" />
|
||||
</children>
|
||||
</GlyphsStack>
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#preferences" text="%menu.preferences">
|
||||
<graphic>
|
||||
@@ -103,14 +126,6 @@
|
||||
<FontAwesomeIconView styleClass="open-icon" />
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button mnemonicParsing="false" onAction="#openConfig">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.open.config" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="config-icon" />
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button fx:id="saveButton" disable="true" mnemonicParsing="false" onAction="#saveCsv">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.save" />
|
||||
@@ -128,6 +143,44 @@
|
||||
</graphic>
|
||||
</Button>
|
||||
</HBox>
|
||||
<Region styleClass="spacer" />
|
||||
<HBox styleClass="segmented-button-bar">
|
||||
<Button fx:id="loadConfigButton" mnemonicParsing="false" disable="true" onAction="#openConfig">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.open.config" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="config-icon" />
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button fx:id="saveConfigButton" disable="true" mnemonicParsing="false" onAction="#saveConfig">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.save.config" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<GlyphsStack>
|
||||
<children>
|
||||
<FontAwesomeIconView styleClass="save-icon" style="-fx-opacity: 0.7;" />
|
||||
<FontAwesomeIconView styleClass="config-icon" />
|
||||
</children>
|
||||
</GlyphsStack>
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button fx:id="saveAsConfigButton" disable="true" mnemonicParsing="false" onAction="#saveAsConfig" styleClass="last" text="...">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.save.as.config" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<GlyphsStack>
|
||||
<children>
|
||||
<FontAwesomeIconView styleClass="save-icon" style="-fx-opacity: 0.7;" />
|
||||
<FontAwesomeIconView styleClass="config-icon" />
|
||||
</children>
|
||||
</GlyphsStack>
|
||||
|
||||
</graphic>
|
||||
</Button>
|
||||
</HBox>
|
||||
<Region styleClass="spacer" />
|
||||
<HBox styleClass="segmented-button-bar">
|
||||
<Button fx:id="deleteRowButton" disable="true" mnemonicParsing="false" onAction="#deleteRow" styleClass="first">
|
||||
|
||||
@@ -48,3 +48,19 @@ validation.message.regexp = does not match {0}
|
||||
validation.message.header.length = number of headers is not correct! there are {0} but there should be {1}
|
||||
validation.message.header.match = header number {0} does not match "{1}" should be "{3}"
|
||||
validation.message.value.of = Value {0} is not part of this list {1}
|
||||
|
||||
validation.rule.label.not_empty = not empty:
|
||||
validation.rule.label.integer = integer:
|
||||
validation.rule.label.double = double:
|
||||
validation.rule.label.minlength = minimum length:
|
||||
validation.rule.label.maxlength = maximum length:
|
||||
validation.rule.label.dateformat = date format:
|
||||
validation.rule.label.alphanumeric = alphanumeric:
|
||||
validation.rule.label.regexp = regular expression:
|
||||
validation.rule.label.value_of = value in list:
|
||||
validation.rule.label.groovy = groovy:
|
||||
validation.rules.active = active
|
||||
|
||||
dialog.validation.rules.title = Validation rules
|
||||
dialog.validation.rules.header = Validation rules of column "{0}"
|
||||
context.menu.edit.column.rules = Edit rules
|
||||
@@ -10,6 +10,9 @@ menu.open.csv = CSV Datei \u00f6ffnen
|
||||
menu.open.config = Pr\u00fcfkonfiguration \u00f6ffnen
|
||||
menu.save = Speichern
|
||||
menu.save.as = Speichern als ...
|
||||
menu.save.config = Pr\u00fcfkonfiguration speichern
|
||||
menu.save.as.config = Pr\u00fcfkonfiguration speichern als ...
|
||||
|
||||
menu.close = Beenden
|
||||
menu.about = \u00dcber ...
|
||||
menu.file = Datei
|
||||
@@ -56,3 +59,20 @@ validation.message.regexp = entspricht nicht dem regul\u00e4ren Ausdruck {0}
|
||||
validation.message.header.length = Anzahl der \u00dcberschriften ist nicht korrekt! Es sind {0} aber es sollten {1} sein
|
||||
validation.message.header.match = \u00dcberschrift in Spalte {0} stimmt nicht. "{1}" sollte "{3}" sein
|
||||
validation.message.value.of = Der Wert {0} ist nicht in der Liste {1} enthalten
|
||||
|
||||
validation.rule.label.not_empty = Nicht leer:
|
||||
validation.rule.label.integer = Zahl:
|
||||
validation.rule.label.double = Gleitkommazahl:
|
||||
validation.rule.label.minlength = Minimale L\u00e4nge:
|
||||
validation.rule.label.maxlength = Maximale L\u00e4nge:
|
||||
validation.rule.label.dateformat = Datumsformat:
|
||||
validation.rule.label.alphanumeric = Nur Zahlen und Buchstaben:
|
||||
validation.rule.label.regexp = Regul\u00e4rer Ausdruck:
|
||||
validation.rule.label.value_of = In der Liste:
|
||||
validation.rule.label.groovy = groovy:
|
||||
validation.rules.active = Aktiv
|
||||
|
||||
dialog.validation.rules.title = Pr\u00fcfregeln
|
||||
dialog.validation.rules.header = Pr\u00fcfregeln f\u00fcr die Spalte "{0}"
|
||||
|
||||
context.menu.edit.column.rules = Pr\u00fcfregeln bearbeiten
|
||||
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.Spinner?>
|
||||
<?import javafx.scene.control.TextArea?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
|
||||
<GridPane hgap="10.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="600.0" vgap="10.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.65">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="NEVER" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints halignment="CENTER" hgrow="NEVER" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<Label text="%validation.rule.label.not_empty" GridPane.rowIndex="1" />
|
||||
<Label text="%validation.rule.label.integer" GridPane.rowIndex="2" />
|
||||
<Label text="%validation.rule.label.double" GridPane.rowIndex="3" />
|
||||
<Label text="%validation.rule.label.minlength" GridPane.rowIndex="5" />
|
||||
<Label text="%validation.rule.label.maxlength" GridPane.rowIndex="6" />
|
||||
<Label text="%validation.rule.label.dateformat" GridPane.rowIndex="7" />
|
||||
<Label text="%validation.rule.label.alphanumeric" GridPane.rowIndex="4" />
|
||||
<Label text="%validation.rule.label.regexp" GridPane.rowIndex="8" />
|
||||
<Label text="%validation.rule.label.value_of" GridPane.rowIndex="9" />
|
||||
<Label text="%validation.rule.label.groovy" GridPane.rowIndex="10" />
|
||||
<CheckBox fx:id="notEmptyRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="1" GridPane.rowIndex="1" />
|
||||
<CheckBox fx:id="integerRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="1" GridPane.rowIndex="2" />
|
||||
<CheckBox fx:id="doublerRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="1" GridPane.rowIndex="3" />
|
||||
<CheckBox fx:id="alphanumericRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="1" GridPane.rowIndex="4" />
|
||||
<Spinner fx:id="minLengthSpinner" GridPane.columnIndex="1" GridPane.rowIndex="5" />
|
||||
<Spinner fx:id="maxLengthSpinner" GridPane.columnIndex="1" GridPane.rowIndex="6" />
|
||||
<TextField fx:id="dateformatRuleTextField" GridPane.columnIndex="1" GridPane.rowIndex="7" />
|
||||
<TextField fx:id="regexpRuleTextField" GridPane.columnIndex="1" GridPane.rowIndex="8" />
|
||||
<TextField fx:id="valueOfRuleTextField" GridPane.columnIndex="1" GridPane.rowIndex="9" />
|
||||
<TextArea fx:id="groovyRuleTextArea" prefHeight="300.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="10" GridPane.rowSpan="2" />
|
||||
<CheckBox fx:id="enableNotEmptyRule" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="1" />
|
||||
<CheckBox fx:id="enableIntegerRule" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="2" />
|
||||
<CheckBox fx:id="enableDoubleRule" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="3" />
|
||||
<CheckBox fx:id="enableAlphanumericRule" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="4" />
|
||||
<CheckBox fx:id="enableMinLengthRule" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="5" />
|
||||
<CheckBox fx:id="enableMaxLengthRule" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="6" />
|
||||
<CheckBox fx:id="enableDateRule" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="7" />
|
||||
<CheckBox fx:id="enableRegexpRule" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="8" />
|
||||
<CheckBox fx:id="enableValueOfRule" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="9" />
|
||||
<CheckBox fx:id="enableGroovyRule" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="10" />
|
||||
<Label text="%validation.rules.active" GridPane.columnIndex="2" />
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
|
||||
</padding>
|
||||
</GridPane>
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
package ninja.javafx.smartcsv.fx.table.model;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationConfiguration;
|
||||
import ninja.javafx.smartcsv.validation.Validator;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -77,20 +78,6 @@ public class CSVModelTest {
|
||||
assertThat(sut.getRows().indexOf(newRow), is(newRow.getRowNumber()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void set_validator_calls_when_model_has_data() {
|
||||
|
||||
// setup
|
||||
Validator validator = mock(Validator.class);
|
||||
setup_model_with_one_row_one_column_and_value();
|
||||
|
||||
// execution
|
||||
sut.setValidator(validator);
|
||||
|
||||
// assertion
|
||||
verify(validator).isValid(TESTHEADER, TESTVALUE, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// private methods
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class ConfigMock {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constants
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private static final String HEADER_SECTION_KEY = "headers";
|
||||
private static final String COLUMN_SECTION_KEY = "columns";
|
||||
private static final String LIST_KEY = "list";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// mocks
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
public static Config headerSectionConfig(String[] headerNames) {
|
||||
|
||||
Config headerSectionConfig = mock(Config.class);
|
||||
Config listConfig = mock(Config.class);
|
||||
|
||||
when(headerSectionConfig.hasPath(HEADER_SECTION_KEY)).thenReturn(true);
|
||||
when(headerSectionConfig.getConfig(HEADER_SECTION_KEY)).thenReturn(listConfig);
|
||||
|
||||
when(listConfig.hasPath(LIST_KEY)).thenReturn(true);
|
||||
when(listConfig.getStringList(LIST_KEY)).thenReturn(asList(headerNames));
|
||||
|
||||
return headerSectionConfig;
|
||||
}
|
||||
|
||||
|
||||
public static Config columnSectionConfig(String column, String validation, Object value) {
|
||||
|
||||
Config columnSectionConfig = mock(Config.class);
|
||||
Config columnConfig = mock(Config.class);
|
||||
Config validatorConfig = mock(Config.class);
|
||||
|
||||
when(columnSectionConfig.hasPath(COLUMN_SECTION_KEY)).thenReturn(true);
|
||||
when(columnSectionConfig.getConfig(COLUMN_SECTION_KEY)).thenReturn(columnConfig);
|
||||
|
||||
when(columnConfig.hasPath(column)).thenReturn(true);
|
||||
when(columnConfig.getConfig(column)).thenReturn(validatorConfig);
|
||||
|
||||
when(validatorConfig.hasPath(validation)).thenReturn(true);
|
||||
if (value instanceof Boolean) {
|
||||
when(validatorConfig.getBoolean(validation)).thenReturn((Boolean) value);
|
||||
} else if (value instanceof String) {
|
||||
when(validatorConfig.getString(validation)).thenReturn((String) value);
|
||||
} else if (value instanceof Integer) {
|
||||
when(validatorConfig.getInt(validation)).thenReturn((Integer) value);
|
||||
} else if (value instanceof List) {
|
||||
when(validatorConfig.getStringList(validation)).thenReturn((List<String>) value);
|
||||
}
|
||||
|
||||
return columnSectionConfig;
|
||||
}
|
||||
}
|
||||
@@ -26,20 +26,19 @@
|
||||
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static ninja.javafx.smartcsv.validation.ConfigMock.headerSectionConfig;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -52,7 +51,7 @@ public class HeaderValidationTest {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parameters
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private Config config;
|
||||
private ValidationConfiguration config;
|
||||
private Boolean expectedResult;
|
||||
private List<ValidationMessage> expectedErrors;
|
||||
private String[] headerNames;
|
||||
@@ -66,11 +65,12 @@ public class HeaderValidationTest {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parameterized constructor
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
public HeaderValidationTest(String[] configHeaderNames,
|
||||
public HeaderValidationTest(String configHeaderNames,
|
||||
String[] headerNames,
|
||||
Boolean expectedResult,
|
||||
List<ValidationMessage> expectedErrors) {
|
||||
this.config = headerSectionConfig(configHeaderNames);
|
||||
Gson gson = new GsonBuilder().create();
|
||||
this.config = gson.fromJson(configHeaderNames, ValidationConfiguration.class);
|
||||
this.headerNames = headerNames;
|
||||
this.expectedResult = expectedResult;
|
||||
this.expectedErrors = expectedErrors;
|
||||
@@ -106,11 +106,16 @@ public class HeaderValidationTest {
|
||||
@Parameterized.Parameters
|
||||
public static Collection validationConfigurations() {
|
||||
return asList(new Object[][] {
|
||||
{ new String[] {}, new String[] {}, true, null },
|
||||
{ new String[] {"a"}, new String[] {"a"}, true, null },
|
||||
{ new String[] {"a"}, new String[] {"b"}, false, singletonList(new ValidationMessage("validation.message.header.match", "0", "a", "b"))},
|
||||
{ new String[] {"a"}, new String[] {"a","b"}, false, singletonList(new ValidationMessage("validation.message.header.length", "2", "1"))},
|
||||
{ new String[] {"a", "b"}, new String[] {"b", "a"}, false, asList(new ValidationMessage("validation.message.header.match", "0", "a", "b"), new ValidationMessage("validation.message.header.match", "1", "b", "a")) }
|
||||
{ json(), new String[] {}, true, null },
|
||||
{ json("a"), new String[] {"a"}, true, null },
|
||||
{ json("a"), new String[] {"b"}, false, singletonList(new ValidationMessage("validation.message.header.match", "0", "a", "b"))},
|
||||
{ json("a"), new String[] {"a","b"}, false, singletonList(new ValidationMessage("validation.message.header.length", "2", "1"))},
|
||||
{ json("a", "b"), new String[] {"b", "a"}, false, asList(new ValidationMessage("validation.message.header.match", "0", "a", "b"), new ValidationMessage("validation.message.header.match", "1", "b", "a")) }
|
||||
});
|
||||
}
|
||||
|
||||
public static String json(String... headerNames) {
|
||||
return "{\"headers\":{\"list\":[" + asList(headerNames).stream().collect(joining(", ")) + "]}}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static ninja.javafx.smartcsv.validation.ConfigMock.columnSectionConfig;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
@@ -23,7 +25,7 @@ public class ValidatorTest {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parameters
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private Config config;
|
||||
private ValidationConfiguration config;
|
||||
private String column;
|
||||
private String value;
|
||||
private Boolean expectedResult;
|
||||
@@ -39,14 +41,14 @@ public class ValidatorTest {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parameterized constructor
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
public ValidatorTest(String configcolumn,
|
||||
String configValidation,
|
||||
Object configValue,
|
||||
public ValidatorTest(String config,
|
||||
String column,
|
||||
String value,
|
||||
Boolean expectedResult,
|
||||
ValidationMessage expectedError) {
|
||||
this.config = columnSectionConfig(configcolumn, configValidation, configValue);
|
||||
System.out.println(config);
|
||||
Gson gson = new GsonBuilder().create();
|
||||
this.config = gson.fromJson(config, ValidationConfiguration.class);
|
||||
this.column = column;
|
||||
this.value = value;
|
||||
this.expectedResult = expectedResult;
|
||||
@@ -84,30 +86,42 @@ public class ValidatorTest {
|
||||
@Parameterized.Parameters
|
||||
public static Collection validationConfigurations() {
|
||||
return asList(new Object[][] {
|
||||
{ "column", "not empty", true, "column", "value", true, null },
|
||||
{ "column", "not empty", true, "column", "", false, new ValidationMessage("validation.message.not.empty") },
|
||||
{ "column", "not empty", true, "column", null, false, new ValidationMessage("validation.message.not.empty") },
|
||||
{ "column", "integer", true, "column", "999", true, null },
|
||||
{ "column", "integer", true, "column", "a", false, new ValidationMessage("validation.message.integer") },
|
||||
{ "column", "double", true, "column", "999", true, null },
|
||||
{ "column", "double", true, "column", "999.000", true, null },
|
||||
{ "column", "double", true, "column", "a", false, new ValidationMessage("validation.message.double") },
|
||||
{ "column", "minlength", 2, "column", "12", true, null },
|
||||
{ "column", "minlength", 2, "column", "1", false, new ValidationMessage("validation.message.min.length", "2") },
|
||||
{ "column", "maxlength", 2, "column", "12", true, null },
|
||||
{ "column", "maxlength", 2, "column", "123", false, new ValidationMessage("validation.message.max.length", "2") },
|
||||
{ "column", "date", "yyyyMMdd", "column", "20151127", true, null },
|
||||
{ "column", "date", "yyyyMMdd", "column", "27.11.2015", false, new ValidationMessage("validation.message.date.format", "yyyyMMdd") },
|
||||
{ "column", "alphanumeric", true, "column", "abcABC123", true, null },
|
||||
{ "column", "alphanumeric", true, "column", "-abcABC123", false, new ValidationMessage("validation.message.alphanumeric") },
|
||||
{ "column", "regexp", "[a-z]*", "column", "abc", true, null },
|
||||
{ "column", "regexp", "[a-z]*", "column", "abcA", false, new ValidationMessage("validation.message.regexp", "[a-z]*") },
|
||||
{ "column", "groovy", "value.contains('a')? 'true' : 'no a inside'", "column", "abcdef", true, null },
|
||||
{ "column", "groovy", "value.contains('a')? 'true' : 'no a inside'", "column", "bcdefg", false, new ValidationMessage("no a inside") },
|
||||
{ "column", "value of", asList("a","b","c","d","e"), "column", "c", true, null },
|
||||
{ "column", "value of", asList("a","b","c","d","e"), "column", "f", false, new ValidationMessage("validation.message.value.of", "f", "a, b, c, d, e") },
|
||||
{ json("column", "not empty", true), "column", "value", true, null },
|
||||
{ json("column", "not empty", true), "column", "", false, new ValidationMessage("validation.message.not.empty") },
|
||||
{ json("column", "not empty", true), "column", null, false, new ValidationMessage("validation.message.not.empty") },
|
||||
{ json("column", "integer", true), "column", "999", true, null },
|
||||
{ json("column", "integer", true), "column", "a", false, new ValidationMessage("validation.message.integer") },
|
||||
{ json("column", "double", true), "column", "999", true, null },
|
||||
{ json("column", "double", true), "column", "999.000", true, null },
|
||||
{ json("column", "double", true), "column", "a", false, new ValidationMessage("validation.message.double") },
|
||||
{ json("column", "minlength", 2), "column", "12", true, null },
|
||||
{ json("column", "minlength", 2), "column", "1", false, new ValidationMessage("validation.message.min.length", "2") },
|
||||
{ json("column", "maxlength", 2), "column", "12", true, null },
|
||||
{ json("column", "maxlength", 2), "column", "123", false, new ValidationMessage("validation.message.max.length", "2") },
|
||||
{ json("column", "date", "yyyyMMdd"), "column", "20151127", true, null },
|
||||
{ json("column", "date", "yyyyMMdd"), "column", "27.11.2015", false, new ValidationMessage("validation.message.date.format", "yyyyMMdd") },
|
||||
{ json("column", "alphanumeric", true), "column", "abcABC123", true, null },
|
||||
{ json("column", "alphanumeric", true), "column", "-abcABC123", false, new ValidationMessage("validation.message.alphanumeric") },
|
||||
{ json("column", "regexp", "[a-z]*"), "column", "abc", true, null },
|
||||
{ json("column", "regexp", "[a-z]*"), "column", "abcA", false, new ValidationMessage("validation.message.regexp", "[a-z]*") },
|
||||
{ json("column", "groovy", "value.contains('a')? 'true' : 'no a inside'"), "column", "abcdef", true, null },
|
||||
{ json("column", "groovy", "value.contains('a')? 'true' : 'no a inside'"), "column", "bcdefg", false, new ValidationMessage("no a inside") },
|
||||
{ json("column", "value of", asList("a","b","c","d","e")), "column", "c", true, null },
|
||||
{ json("column", "value of", asList("a","b","c","d","e")), "column", "f", false, new ValidationMessage("validation.message.value.of", "f", "a, b, c, d, e") },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static String json(String column, String rule, Object value) {
|
||||
String json = "{\"columns\":{\"" + column + "\":{\"" + rule + "\":";
|
||||
if (value instanceof String) {
|
||||
json += "\""+ value + "\"";
|
||||
} else if (value instanceof List) {
|
||||
List<String> list = (List<String>)value;
|
||||
json += "[" + list.stream().collect(joining(", ")) + "]";
|
||||
} else {
|
||||
json += value;
|
||||
}
|
||||
json += "}}}";
|
||||
return json;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user