Merge branch 'editable_column_rules'

This commit is contained in:
Andreas Billmann
2016-02-05 09:44:51 +01:00
22 changed files with 1058 additions and 289 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -47,4 +47,20 @@ 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.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

View File

@@ -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
@@ -55,4 +58,21 @@ 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.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

View File

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

View File

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

View File

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

View File

@@ -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(", ")) + "]}}";
}
}

View File

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