14 Commits
0.5 ... 0.7

Author SHA1 Message Date
e6742a4e30 error export implemented and message on error side bar includes column name 2016-08-10 23:41:47 +02:00
7472c66823 fixed uniqueness validation and renamed the abstract class when empty values are valid 2016-08-09 21:17:29 +02:00
c7873ef0ba unique validation has to work on the model to have the correct snapshot of the data 2016-08-09 20:59:29 +02:00
b79a20201e removed the special treatment of NotEmptyValidation 2016-08-09 20:59:29 +02:00
Andreas Billmann
3ebf78805c Update README.md 2016-08-08 17:23:02 +02:00
dcdea4236f version 0.6 2016-08-08 17:14:51 +02:00
11358c5bec Merge remote-tracking branch 'remotes/origin/validation_algorithm_revisited' 2016-08-08 17:12:25 +02:00
9c21357059 the error color should be more red 2016-08-08 17:11:11 +02:00
909617d9b7 Merge remote-tracking branch 'remotes/origin/validation_algorithm_revisited' 2016-08-07 23:41:26 +02:00
ab952aa98f optimized imports based on intellij IDEA 2016-08-07 23:13:47 +02:00
a7bd8d5a3e revisted the model to speed up the validation and to have a better control how much revalitaions have to be done when something changes 2016-08-07 23:13:02 +02:00
bc59f08bbb first version of new validation algorithm, that is a lot faster 2016-08-07 16:57:55 +02:00
4c4d25f3b5 little performance optimization (less method calls) 2016-08-06 21:41:14 +02:00
6af20575e8 uniqueness validation is now also supported by the validation rules editor 2016-08-05 23:45:23 +02:00
52 changed files with 1180 additions and 453 deletions

View File

@@ -14,7 +14,7 @@ even in a "normal" CSV editor. So I decided to write this simple JavaFX applicat
[Wiki & Documentation](https://github.com/frosch95/SmartCSV.fx/wiki) [Wiki & Documentation](https://github.com/frosch95/SmartCSV.fx/wiki)
binary distribution of the [latest release (0.5)](https://drive.google.com/file/d/0BwY9gBUvn5qmejllOTRwbEJYdDA/view?usp=sharing) binary distribution of the [latest release (0.6)](https://github.com/frosch95/SmartCSV.fx/releases/download/0.6/SmartCSV.fx-0.6-SNAPSHOT.zip)
##Talks ##Talks
[Introduction](http://javafx.ninja/talks/introduction/) [Introduction](http://javafx.ninja/talks/introduction/)

View File

@@ -1,5 +1,5 @@
group 'ninja.javafx' group 'ninja.javafx'
version '0.5-SNAPSHOT' version '0.7-SNAPSHOT'
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'groovy' apply plugin: 'groovy'

View File

@@ -29,7 +29,6 @@ package ninja.javafx.smartcsv.csv;
import ninja.javafx.smartcsv.FileReader; import ninja.javafx.smartcsv.FileReader;
import ninja.javafx.smartcsv.fx.table.model.CSVModel; import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.fx.table.model.CSVRow; import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import org.springframework.stereotype.Service;
import org.supercsv.io.CsvMapReader; import org.supercsv.io.CsvMapReader;
import org.supercsv.io.ICsvMapReader; import org.supercsv.io.ICsvMapReader;
@@ -60,7 +59,7 @@ public class CSVFileReader extends CSVConfigurable implements FileReader<CSVMode
while ((customerMap = mapReader.read(header)) != null) { while ((customerMap = mapReader.read(header)) != null) {
CSVRow row = model.addRow(); CSVRow row = model.addRow();
for (String column : header) { for (String column : header) {
row.addValue(column, customerMap.get(column)); model.addValue(row, column, customerMap.get(column));
} }
} }

View File

@@ -28,7 +28,6 @@ package ninja.javafx.smartcsv.csv;
import ninja.javafx.smartcsv.fx.table.model.CSVModel; import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.fx.table.model.CSVRow; import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import org.springframework.stereotype.Service;
import org.supercsv.io.CsvMapWriter; import org.supercsv.io.CsvMapWriter;
import org.supercsv.io.ICsvMapWriter; import org.supercsv.io.ICsvMapWriter;

View File

@@ -0,0 +1,71 @@
package ninja.javafx.smartcsv.export;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.validation.ValidationError;
import java.io.File;
import java.io.StringWriter;
import java.nio.file.Files;
import java.util.ResourceBundle;
import static java.text.MessageFormat.format;
import static ninja.javafx.smartcsv.fx.util.I18nValidationUtil.getI18nValidatioMessage;
/**
* this class exports the error messages into a log file
*/
@org.springframework.stereotype.Service
public class ErrorExport extends Service {
private CSVModel model;
private File file;
private ResourceBundle resourceBundle;
private String csvFilename;
public void setCsvFilename(String csvFilename) {
this.csvFilename = csvFilename;
}
public void setResourceBundle(ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
}
public void setModel(CSVModel model) {
this.model = model;
}
public void setFile(File file) {
this.file = file;
}
@Override
protected Task createTask() {
return new Task() {
@Override
protected Void call() throws Exception {
try {
StringWriter log = new StringWriter();
log.append(
format(resourceBundle.getString("log.header.message"),
csvFilename,
Integer.toString(model.getValidationError().size()))).append("\n\n");
for (ValidationError error:model.getValidationError()) {
log.append(
format(resourceBundle.getString("log.message"),
error.getLineNumber().toString(),
error.getColumn(),
getI18nValidatioMessage(resourceBundle, error))).append("\n");
}
Files.write(file.toPath(), log.toString().getBytes());
} catch (Throwable ex) {
ex.printStackTrace();
}
return null;
}
};
}
}

View File

@@ -28,11 +28,9 @@ package ninja.javafx.smartcsv.fx;
import javafx.application.Application; import javafx.application.Application;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.scene.Parent; import javafx.scene.Parent;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import ninja.javafx.smartcsv.fx.about.AboutController; import ninja.javafx.smartcsv.fx.about.AboutController;
import org.springframework.context.annotation.*; import org.springframework.context.annotation.*;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

View File

@@ -26,10 +26,7 @@
package ninja.javafx.smartcsv.fx; package ninja.javafx.smartcsv.fx;
import javafx.beans.InvalidationListener; import javafx.beans.binding.Bindings;
import javafx.beans.Observable;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import javafx.collections.WeakListChangeListener; import javafx.collections.WeakListChangeListener;
import javafx.concurrent.WorkerStateEvent; import javafx.concurrent.WorkerStateEvent;
@@ -41,9 +38,9 @@ import javafx.scene.control.*;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import javafx.util.converter.NumberStringConverter;
import ninja.javafx.smartcsv.csv.CSVFileReader; import ninja.javafx.smartcsv.csv.CSVFileReader;
import ninja.javafx.smartcsv.csv.CSVFileWriter; import ninja.javafx.smartcsv.csv.CSVFileWriter;
import ninja.javafx.smartcsv.export.ErrorExport;
import ninja.javafx.smartcsv.files.FileStorage; import ninja.javafx.smartcsv.files.FileStorage;
import ninja.javafx.smartcsv.fx.about.AboutController; import ninja.javafx.smartcsv.fx.about.AboutController;
import ninja.javafx.smartcsv.fx.list.ErrorSideBar; import ninja.javafx.smartcsv.fx.list.ErrorSideBar;
@@ -71,11 +68,9 @@ import org.supercsv.prefs.CsvPreference;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.text.MessageFormat;
import java.util.Optional; import java.util.Optional;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import static java.lang.Integer.parseInt;
import static java.lang.Math.max; import static java.lang.Math.max;
import static java.text.MessageFormat.format; import static java.text.MessageFormat.format;
import static javafx.application.Platform.exit; import static javafx.application.Platform.exit;
@@ -102,6 +97,9 @@ public class SmartCSVController extends FXMLController {
public static final String CSV_FILTER_EXTENSION = "*.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_TEXT = "JSON files (*.json)";
public static final String JSON_FILTER_EXTENSION = "*.json"; public static final String JSON_FILTER_EXTENSION = "*.json";
public static final String EXPORT_LOG_FILTER_TEXT = "Error log files (*.log)";
public static final String EXPORT_LOG_FILTER_EXTENSION = "*.log";
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// injections // injections
@@ -122,6 +120,9 @@ public class SmartCSVController extends FXMLController {
@Autowired @Autowired
private SaveFileService saveFileService; private SaveFileService saveFileService;
@Autowired
private ErrorExport errorExport;
@FXML @FXML
private BorderPane applicationPane; private BorderPane applicationPane;
@@ -164,6 +165,9 @@ public class SmartCSVController extends FXMLController {
@FXML @FXML
private MenuItem gotoLineMenuItem; private MenuItem gotoLineMenuItem;
@FXML
private MenuItem exportMenuItem;
@FXML @FXML
private Button saveButton; private Button saveButton;
@@ -188,6 +192,9 @@ public class SmartCSVController extends FXMLController {
@FXML @FXML
private Button addRowButton; private Button addRowButton;
@FXML
private Button exportButton;
@FXML @FXML
private Label currentLineNumber; private Label currentLineNumber;
@@ -352,7 +359,7 @@ public class SmartCSVController extends FXMLController {
public void addRow(ActionEvent actionEvent) { public void addRow(ActionEvent actionEvent) {
CSVRow row = currentCsvFile.getContent().addRow(); CSVRow row = currentCsvFile.getContent().addRow();
for (String column : currentCsvFile.getContent().getHeader()) { for (String column : currentCsvFile.getContent().getHeader()) {
row.addValue(column, ""); currentCsvFile.getContent().addValue(row, column, "");
} }
currentCsvFile.setFileChanged(true); currentCsvFile.setFileChanged(true);
resetContent(); resetContent();
@@ -377,6 +384,26 @@ public class SmartCSVController extends FXMLController {
} }
} }
@FXML
public void export(ActionEvent actionEvent) {
final FileChooser fileChooser = new FileChooser();
//Set extension filter
final FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(EXPORT_LOG_FILTER_TEXT, EXPORT_LOG_FILTER_EXTENSION);
fileChooser.getExtensionFilters().add(extFilter);
fileChooser.setTitle("Save");
//Show open file dialog
File file = fileChooser.showSaveDialog(applicationPane.getScene().getWindow());
if (file != null) {
errorExport.setCsvFilename(currentCsvFile.getFile().getName());
errorExport.setModel(currentCsvFile.getContent());
errorExport.setFile(file);
errorExport.setResourceBundle(resourceBundle);
errorExport.restart();
}
}
public boolean canExit() { public boolean canExit() {
boolean canExit = true; boolean canExit = true;
if (currentCsvFile.getContent() != null && currentCsvFile.isFileChanged()) { if (currentCsvFile.getContent() != null && currentCsvFile.isFileChanged()) {
@@ -408,7 +435,7 @@ public class SmartCSVController extends FXMLController {
runLater(() -> { runLater(() -> {
validationEditorController.updateConfiguration(); validationEditorController.updateConfiguration();
currentCsvFile.setFileChanged(true); currentCsvFile.setFileChanged(true);
currentCsvFile.getContent().revalidate(); currentCsvFile.getContent().revalidate(column);
}); });
} }
} }
@@ -559,6 +586,8 @@ public class SmartCSVController extends FXMLController {
* Creates new table view and add the new content * Creates new table view and add the new content
*/ */
private void resetContent() { private void resetContent() {
resetExportButtons();
if (currentCsvFile.getContent() != null) { if (currentCsvFile.getContent() != null) {
currentCsvFile.getContent().getValidationError().addListener(weakErrorListListener); currentCsvFile.getContent().getValidationError().addListener(weakErrorListListener);
currentCsvFile.getContent().setValidationConfiguration(currentConfigFile.getContent()); currentCsvFile.getContent().setValidationConfiguration(currentConfigFile.getContent());
@@ -582,15 +611,28 @@ public class SmartCSVController extends FXMLController {
setRightAnchor(tableView, 0.0); setRightAnchor(tableView, 0.0);
tableWrapper.getChildren().setAll(tableView); tableWrapper.getChildren().setAll(tableView);
errorSideBar.setModel(currentCsvFile.getContent()); errorSideBar.setModel(currentCsvFile.getContent());
binExportButtons();
} }
} }
private void binExportButtons() {
exportButton.disableProperty().bind(Bindings.isEmpty(currentCsvFile.getContent().getValidationError()));
exportMenuItem.disableProperty().bind(Bindings.isEmpty(currentCsvFile.getContent().getValidationError()));
}
private void resetExportButtons() {
exportButton.disableProperty().unbind();
exportMenuItem.disableProperty().unbind();
exportButton.disableProperty().setValue(true);
exportMenuItem.disableProperty().setValue(true);
}
/** /**
* Adds a column with the given name to the tableview * Adds a column with the given name to the tableview
* @param header name of the column header * @param header name of the column header
* @param tableView the tableview * @param tableView the tableview
*/ */
private void addColumn(String header, TableView tableView) { private void addColumn(final String header, TableView tableView) {
TableColumn column = new TableColumn(header); TableColumn column = new TableColumn(header);
column.setCellValueFactory(new ObservableMapValueFactory(header)); column.setCellValueFactory(new ObservableMapValueFactory(header));
column.setCellFactory(cellFactory); column.setCellFactory(cellFactory);
@@ -607,7 +649,6 @@ public class SmartCSVController extends FXMLController {
getColumns().get(header).setValue(event.getNewValue()); getColumns().get(header).setValue(event.getNewValue());
runLater(() -> { runLater(() -> {
currentCsvFile.setFileChanged(true); currentCsvFile.setFileChanged(true);
currentCsvFile.getContent().revalidate();
}); });
} }
}); });

View File

@@ -36,7 +36,6 @@ import javafx.scene.layout.Region;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import ninja.javafx.smartcsv.fx.table.model.CSVModel; import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.fx.util.ColorConstants;
import ninja.javafx.smartcsv.validation.ValidationError; import ninja.javafx.smartcsv.validation.ValidationError;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -49,7 +48,7 @@ import java.util.ResourceBundle;
import static javafx.geometry.Pos.CENTER; import static javafx.geometry.Pos.CENTER;
import static ninja.javafx.smartcsv.fx.util.ColorConstants.ERROR_COLOR; import static ninja.javafx.smartcsv.fx.util.ColorConstants.ERROR_COLOR;
import static ninja.javafx.smartcsv.fx.util.ColorConstants.OK_COLOR; import static ninja.javafx.smartcsv.fx.util.ColorConstants.OK_COLOR;
import static ninja.javafx.smartcsv.fx.util.I18nValidationUtil.getI18nValidatioMessage; import static ninja.javafx.smartcsv.fx.util.I18nValidationUtil.getI18nValidatioMessageWithColumn;
/** /**
* clickable side bar with error markers * clickable side bar with error markers
@@ -159,7 +158,7 @@ public class ErrorSideBar extends Region {
errorMarker.setStyle("-fx-background-color: " + ERROR_COLOR); errorMarker.setStyle("-fx-background-color: " + ERROR_COLOR);
errorMarker.setOnMouseClicked(event -> selectedValidationError.setValue(error)); errorMarker.setOnMouseClicked(event -> selectedValidationError.setValue(error));
errorMarker.setOnMouseEntered(event -> { errorMarker.setOnMouseEntered(event -> {
popOver.setContentNode(popupContent(getI18nValidatioMessage(resourceBundle, error))); popOver.setContentNode(popupContent(getI18nValidatioMessageWithColumn(resourceBundle, error)));
popOver.show(errorMarker, -16); popOver.show(errorMarker, -16);
}); });
return errorMarker; return errorMarker;

View File

@@ -1,6 +1,5 @@
package ninja.javafx.smartcsv.fx.list; package ninja.javafx.smartcsv.fx.list;
import com.sun.javafx.scene.control.skin.resources.ControlResources;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.control.*; import javafx.scene.control.*;

View File

@@ -33,7 +33,6 @@ import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import ninja.javafx.smartcsv.fx.table.model.CSVRow; import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import ninja.javafx.smartcsv.fx.table.model.CSVValue; import ninja.javafx.smartcsv.fx.table.model.CSVValue;
import ninja.javafx.smartcsv.fx.util.ColorConstants;
import java.util.ResourceBundle; import java.util.ResourceBundle;

View File

@@ -28,22 +28,18 @@ package ninja.javafx.smartcsv.fx.table.model;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.concurrent.Service; import ninja.javafx.smartcsv.validation.RevalidationService;
import javafx.concurrent.Task;
import ninja.javafx.smartcsv.validation.ValidationConfiguration; import ninja.javafx.smartcsv.validation.ValidationConfiguration;
import ninja.javafx.smartcsv.validation.ValidationError; import ninja.javafx.smartcsv.validation.ValidationError;
import ninja.javafx.smartcsv.validation.Validator; import ninja.javafx.smartcsv.validation.Validator;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
/** /**
* The CSVModel is the client representation for the csv filepath. * The CSVModel is the client representation for the csv filepath.
* It holds the data in rows, stores the header and manages the validator. * It holds the data in rows, stores the header and manages the validator.
*/ */
public class CSVModel { public final class CSVModel implements ColumnValueProvider {
private static final Logger logger = LogManager.getLogger(CSVModel.class); private static final Logger logger = LogManager.getLogger(CSVModel.class);
@@ -55,15 +51,17 @@ public class CSVModel {
/** /**
* sets the validator configuration for the data revalidates * sets the validator configuration for the data revalidates
*
* @param validationConfiguration the validator configuration for this data * @param validationConfiguration the validator configuration for this data
*/ */
public void setValidationConfiguration(ValidationConfiguration validationConfiguration) { public void setValidationConfiguration(ValidationConfiguration validationConfiguration) {
this.validator = new Validator(validationConfiguration); this.validator = new Validator(validationConfiguration, this);
revalidate(); revalidate();
} }
/** /**
* returns the data as a list of rows of the * returns the data as a list of rows of the
*
* @return list of rows * @return list of rows
*/ */
public ObservableList<CSVRow> getRows() { public ObservableList<CSVRow> getRows() {
@@ -76,18 +74,30 @@ public class CSVModel {
/** /**
* adds a new and empty row * adds a new and empty row
*
* @return the new row * @return the new row
*/ */
public CSVRow addRow() { public CSVRow addRow() {
CSVRow row = new CSVRow(); CSVRow row = new CSVRow();
row.setValidator(validator);
row.setRowNumber(rows.size()); row.setRowNumber(rows.size());
rows.add(row); rows.add(row);
return row; return row;
} }
public void addValue(final CSVRow row, final String column, final String value) {
final CSVValue csvValue = row.addValue(column, value);
csvValue.valueProperty().addListener(observable -> {
if (validator.needsColumnValidation(column)) {
revalidate();
} else {
csvValue.setValidationError(validator.isValid(row.getRowNumber(), column, csvValue.getValue()));
}
});
}
/** /**
* sets the column headers as string array * sets the column headers as string array
*
* @param header the headers of the columns * @param header the headers of the columns
*/ */
public void setHeader(String[] header) { public void setHeader(String[] header) {
@@ -97,6 +107,7 @@ public class CSVModel {
/** /**
* returns the column headers * returns the column headers
*
* @return the column headers * @return the column headers
*/ */
public String[] getHeader() { public String[] getHeader() {
@@ -104,6 +115,12 @@ public class CSVModel {
} }
public void revalidate(String column) {
if (!hasValidator()) return;
validator.reinitializeColumn(column);
revalidate();
}
/** /**
* walks through the data and validates each value * walks through the data and validates each value
*/ */
@@ -113,8 +130,6 @@ public class CSVModel {
logger.info("revalidate: hasValidator -> {}", hasValidator()); logger.info("revalidate: hasValidator -> {}", hasValidator());
if (!hasValidator()) return; if (!hasValidator()) return;
validator.clearScriptCache();
revalidationService.setHeader(header); revalidationService.setHeader(header);
revalidationService.setRows(rows); revalidationService.setRows(rows);
revalidationService.setValidator(validator); revalidationService.setValidator(validator);
@@ -130,71 +145,19 @@ public class CSVModel {
public ValidationConfiguration createValidationConfiguration() { public ValidationConfiguration createValidationConfiguration() {
ValidationConfiguration newValidationConfiguration = new ValidationConfiguration(); ValidationConfiguration newValidationConfiguration = new ValidationConfiguration();
newValidationConfiguration.setHeaderNames(this.header); newValidationConfiguration.setHeaderNames(this.header);
this.validator = new Validator(newValidationConfiguration); this.validator = new Validator(newValidationConfiguration, this);
this.revalidate(); this.revalidate();
return newValidationConfiguration; return newValidationConfiguration;
} }
private static class RevalidationService extends Service<List<ValidationError>> {
private Validator validator; @Override
private List<CSVRow> rows; public String getValue(int row, String column) {
private String[] header; return rows.get(row).getColumns().get(column).getValue().getValue();
public void setValidator(Validator validator) {
this.validator = validator;
}
public void setRows(List<CSVRow> rows) {
this.rows = rows;
}
public void setHeader(String[] header) {
this.header = header;
} }
@Override @Override
protected Task<List<ValidationError>> createTask() { public int getNumberOfRows() {
return new Task<List<ValidationError>>() { return rows.size();
@Override
protected List<ValidationError> call() throws Exception {
List<ValidationError> errors = new ArrayList<>();
try {
if (header != null) {
ValidationError headerError = validator.isHeaderValid(header);
if (headerError != null) {
logger.info("revalidate: header error found");
errors.add(headerError);
} }
}
for (int lineNumber = 0; lineNumber < rows.size(); lineNumber++) {
CSVRow row = rows.get(lineNumber);
row.setValidator(validator);
for (String column : row.getColumns().keySet()) {
CSVValue value = row.getColumns().get(column).getValue();
value.setValidator(validator);
if (validator != null) {
ValidationError validationError = validator.isValid(column, value.getValue(), lineNumber);
if (validationError != null) {
logger.info("revalidate: {} errors found in line {}", validationError.getMessages().size(), lineNumber);
errors.add(validationError);
value.setValidationError(validationError);
} else {
value.setValidationError(null);
}
} else {
value.setValidationError(null);
}
}
}
} catch (Throwable t) {
logger.error("validation error", t);
}
return errors;
}
};
}
}
} }

View File

@@ -30,24 +30,14 @@ import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableMap; import javafx.collections.ObservableMap;
import ninja.javafx.smartcsv.validation.Validator;
/** /**
* This class represents a single row in the csv file. * This class represents a single row in the csv file.
*/ */
public class CSVRow { public class CSVRow {
private Validator validator;
private ObservableMap<String, ObjectProperty<CSVValue>> columns = FXCollections.observableHashMap(); private ObservableMap<String, ObjectProperty<CSVValue>> columns = FXCollections.observableHashMap();
private int rowNumber; private int rowNumber;
/**
* single row
* @param validator the reference to the validator
*/
public void setValidator(Validator validator) {
this.validator = validator;
}
/** /**
* sets the row number * sets the row number
* @param rowNumber * @param rowNumber
@@ -78,13 +68,11 @@ public class CSVRow {
* @param column column name * @param column column name
* @param value the value to store * @param value the value to store
*/ */
public void addValue(String column, String value) { CSVValue addValue(String column, String value) {
CSVValue v = new CSVValue(); CSVValue v = new CSVValue();
v.setValidator(validator);
v.setColumn(column);
v.setRowNumber(rowNumber);
v.setValue(value); v.setValue(value);
columns.put(column, new SimpleObjectProperty<>(v)); columns.put(column, new SimpleObjectProperty<>(v));
return v;
} }
} }

View File

@@ -29,7 +29,6 @@ package ninja.javafx.smartcsv.fx.table.model;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
import ninja.javafx.smartcsv.validation.ValidationError; import ninja.javafx.smartcsv.validation.ValidationError;
import ninja.javafx.smartcsv.validation.Validator;
/** /**
* The csv value represents the value of a single cell. * The csv value represents the value of a single cell.
@@ -37,36 +36,9 @@ import ninja.javafx.smartcsv.validation.Validator;
* and if the value is valid based on the validator. * and if the value is valid based on the validator.
*/ */
public class CSVValue { public class CSVValue {
private Validator validator;
private int rowNumber;
private String column;
private StringProperty value = new SimpleStringProperty(); private StringProperty value = new SimpleStringProperty();
private ValidationError valid; private ValidationError valid;
/**
* single value of a cell
* @param validator the reference to the validator
*/
public void setValidator(Validator validator) {
this.validator = validator;
}
/**
* the row number this value is stored in
* @param row row number
*/
public void setRowNumber(int row) {
this.rowNumber = row;
}
/**
* the column this value is stored in
* @param column header name of the column
*/
public void setColumn(String column) {
this.column = column;
}
/** /**
* returns the real value * returns the real value
* @return the real value * @return the real value
@@ -88,9 +60,6 @@ public class CSVValue {
* @param value the real value * @param value the real value
*/ */
public void setValue(String value) { public void setValue(String value) {
if (validator != null) {
valid = validator.isValid(column, value, rowNumber);
}
this.value.set(value); this.value.set(value);
} }
@@ -106,7 +75,7 @@ public class CSVValue {
* sets the state if a value is valid or not * sets the state if a value is valid or not
* @param valid the validation state * @param valid the validation state
*/ */
protected void setValidationError(ValidationError valid) { public void setValidationError(ValidationError valid) {
this.valid = valid; this.valid = valid;
} }
} }

View File

@@ -0,0 +1,11 @@
package ninja.javafx.smartcsv.fx.table.model;
/**
* interface for easier access to values in a column
*/
public interface ColumnValueProvider {
String getValue(int row, String column);
int getNumberOfRows();
}

View File

@@ -31,5 +31,5 @@ package ninja.javafx.smartcsv.fx.util;
*/ */
public class ColorConstants { public class ColorConstants {
public static final String OK_COLOR = "#22aa22"; public static final String OK_COLOR = "#22aa22";
public static final String ERROR_COLOR = "#ff6622"; public static final String ERROR_COLOR = "#ff3333";
} }

View File

@@ -54,15 +54,24 @@ public class I18nValidationUtil {
return ""; return "";
} }
public static String getI18nValidatioMessageWithColumn(ResourceBundle resourceBundle, ValidationError error) {
return getI18nValidatioMessage(resourceBundle, error, resourceBundle.getString("column") + " " + error.getColumn() + " : ");
}
public static String getI18nValidatioMessage(ResourceBundle resourceBundle, ValidationError error) { public static String getI18nValidatioMessage(ResourceBundle resourceBundle, ValidationError error) {
return getI18nValidatioMessage(resourceBundle, error, "");
}
private static String getI18nValidatioMessage(ResourceBundle resourceBundle, ValidationError error, String prefix) {
List<ValidationMessage> validationMessages = error.getMessages(); List<ValidationMessage> validationMessages = error.getMessages();
StringWriter message = new StringWriter(); StringWriter message = new StringWriter();
for (ValidationMessage validationMessage: validationMessages) { for (ValidationMessage validationMessage: validationMessages) {
message.append(prefix);
if (resourceBundle.containsKey(validationMessage.getKey())) { if (resourceBundle.containsKey(validationMessage.getKey())) {
String resourceText = resourceBundle.getString(validationMessage.getKey()); String resourceText = resourceBundle.getString(validationMessage.getKey());
if (validationMessage.getParameters().length > 0) { if (validationMessage.getParameters().length > 0) {
message.append(format(resourceText, validationMessage.getParameters())).append("\n"); message.append(format(resourceText, (Object[]) validationMessage.getParameters())).append("\n");
} else { } else {
message.append(resourceText).append("\n"); message.append(resourceText).append("\n");
} }

View File

@@ -28,11 +28,8 @@ package ninja.javafx.smartcsv.fx.util;
import javafx.concurrent.Service; import javafx.concurrent.Service;
import javafx.concurrent.Task; import javafx.concurrent.Task;
import ninja.javafx.smartcsv.FileReader;
import ninja.javafx.smartcsv.files.FileStorage; import ninja.javafx.smartcsv.files.FileStorage;
import java.io.File;
/** /**
* Service class for async load of a csv file * Service class for async load of a csv file
*/ */

View File

@@ -28,14 +28,8 @@ package ninja.javafx.smartcsv.fx.util;
import javafx.concurrent.Service; import javafx.concurrent.Service;
import javafx.concurrent.Task; import javafx.concurrent.Task;
import ninja.javafx.smartcsv.FileWriter;
import ninja.javafx.smartcsv.csv.CSVFileWriter;
import ninja.javafx.smartcsv.files.FileStorage; import ninja.javafx.smartcsv.files.FileStorage;
import java.io.File;
import static javafx.application.Platform.runLater;
/** /**
* Service class for async load of a csv file * Service class for async load of a csv file
*/ */

View File

@@ -107,6 +107,9 @@ public class ValidationEditorController extends FXMLController {
@FXML @FXML
private CheckBox alphanumericRuleCheckBox; private CheckBox alphanumericRuleCheckBox;
@FXML
private CheckBox uniqueRuleCheckBox;
@FXML @FXML
private Spinner<Integer> minLengthSpinner; private Spinner<Integer> minLengthSpinner;
@@ -155,6 +158,9 @@ public class ValidationEditorController extends FXMLController {
@FXML @FXML
private CheckBox enableGroovyRule; private CheckBox enableGroovyRule;
@FXML
private CheckBox enableUniqueRule;
@Value("${fxml.smartcvs.validation.editor.view}") @Value("${fxml.smartcvs.validation.editor.view}")
@Override @Override
@@ -172,6 +178,7 @@ public class ValidationEditorController extends FXMLController {
initCheckBox(integerRuleCheckBox, enableIntegerRule); initCheckBox(integerRuleCheckBox, enableIntegerRule);
initCheckBox(doublerRuleCheckBox, enableDoubleRule); initCheckBox(doublerRuleCheckBox, enableDoubleRule);
initCheckBox(alphanumericRuleCheckBox, enableAlphanumericRule); initCheckBox(alphanumericRuleCheckBox, enableAlphanumericRule);
initCheckBox(uniqueRuleCheckBox, enableUniqueRule);
initSpinner(minLengthSpinner, enableMinLengthRule); initSpinner(minLengthSpinner, enableMinLengthRule);
initSpinner(maxLengthSpinner, enableMaxLengthRule); initSpinner(maxLengthSpinner, enableMaxLengthRule);
initTextInputControl(dateformatRuleTextField, enableDateRule); initTextInputControl(dateformatRuleTextField, enableDateRule);
@@ -214,6 +221,12 @@ public class ValidationEditorController extends FXMLController {
validationConfiguration.setNotEmptyRuleFor(selectedColumn.getValue(), null); validationConfiguration.setNotEmptyRuleFor(selectedColumn.getValue(), null);
} }
if (enableUniqueRule.isSelected()) {
validationConfiguration.setUniqueRuleFor(selectedColumn.getValue(), uniqueRuleCheckBox.isSelected());
} else {
validationConfiguration.setUniqueRuleFor(selectedColumn.getValue(), null);
}
if (enableDoubleRule.isSelected()) { if (enableDoubleRule.isSelected()) {
validationConfiguration.setDoubleRuleFor(selectedColumn.getValue(), doublerRuleCheckBox.isSelected()); validationConfiguration.setDoubleRuleFor(selectedColumn.getValue(), doublerRuleCheckBox.isSelected());
} else { } else {
@@ -261,6 +274,8 @@ public class ValidationEditorController extends FXMLController {
} else { } else {
validationConfiguration.setValueOfRuleFor(selectedColumn.getValue(), null); validationConfiguration.setValueOfRuleFor(selectedColumn.getValue(), null);
} }
} }
private void updateForm() { private void updateForm() {
@@ -289,6 +304,12 @@ public class ValidationEditorController extends FXMLController {
enableAlphanumericRule enableAlphanumericRule
); );
updateCheckBox(
uniqueRuleCheckBox,
validationConfiguration.getUniqueRuleFor(getSelectedColumn()),
enableUniqueRule
);
updateSpinner( updateSpinner(
minLengthSpinner, minLengthSpinner,
validationConfiguration.getMinLengthRuleFor(getSelectedColumn()), validationConfiguration.getMinLengthRuleFor(getSelectedColumn()),

View File

@@ -28,7 +28,6 @@ package ninja.javafx.smartcsv.preferences;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileReader; import ninja.javafx.smartcsv.FileReader;
import org.springframework.stereotype.Service;
import org.supercsv.prefs.CsvPreference; import org.supercsv.prefs.CsvPreference;
import org.supercsv.quote.AlwaysQuoteMode; import org.supercsv.quote.AlwaysQuoteMode;

View File

@@ -29,7 +29,6 @@ package ninja.javafx.smartcsv.preferences;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileWriter; import ninja.javafx.smartcsv.FileWriter;
import org.springframework.stereotype.Service;
import org.supercsv.prefs.CsvPreference; import org.supercsv.prefs.CsvPreference;
import java.io.File; import java.io.File;

View File

@@ -0,0 +1,47 @@
/*
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 static org.apache.commons.validator.GenericValidator.matchRegexp;
/**
* Checks if the value is alpha numeric
*/
public class AlphaNumericValidation extends EmptyValueIsValid {
@Override
public void check(int row, String value, ValidationError error) {
if (!matchRegexp(value, "[0-9a-zA-Z]*")) {
error.add("validation.message.alphanumeric");
}
}
@Override
public Type getType() {
return Type.ALPHANUMERIC;
}
}

View File

@@ -0,0 +1,53 @@
/*
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 static org.apache.commons.validator.GenericValidator.isDate;
/**
* Checks if the date has the right format
*/
public class DateValidation extends EmptyValueIsValid {
private String dateformat;
public DateValidation(String dateformat) {
assert dateformat != null && !dateformat.trim().isEmpty() : "empty date format for date validation";
this.dateformat = dateformat;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!isDate(value, dateformat, true)) {
error.add("validation.message.date.format", dateformat);
}
}
@Override
public Type getType() {
return Type.DATE;
}
}

View File

@@ -0,0 +1,46 @@
/*
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 static org.apache.commons.validator.GenericValidator.isDouble;
/**
* Checks if the value is a double
*/
public class DoubleValidation extends EmptyValueIsValid {
@Override
public void check(int row, String value, ValidationError error) {
if (!isDouble(value)) {
error.add("validation.message.double");
}
}
@Override
public Type getType() {
return Type.DOUBLE;
}
}

View File

@@ -0,0 +1,12 @@
package ninja.javafx.smartcsv.validation;
/**
* validations based on this are not validated when the value is null or empty
*/
public abstract class EmptyValueIsValid implements Validation {
@Override
public boolean canBeChecked(String value) {
return value != null && !value.isEmpty();
}
}

View File

@@ -0,0 +1,78 @@
/*
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 groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import org.codehaus.groovy.control.CompilationFailedException;
/**
* Executes the given groovy as check
*/
public class GroovyValidation extends EmptyValueIsValid {
private String groovyScript;
private GroovyShell shell = new GroovyShell();
private Script script;
public GroovyValidation(String groovyScript) {
this.groovyScript = groovyScript;
script = shell.parse(groovyScript);
}
@Override
public void check(int row, String value, ValidationError error) {
Binding binding = new Binding();
binding.setVariable("value", value);
script.setBinding(binding);
Object groovyResult = null;
try {
groovyResult = script.run();
} catch (CompilationFailedException e) {
error.add("validation.message.groovy.exception", groovyScript, e.getMessage());
e.printStackTrace();
}
if (groovyResult == null) {
error.add("validation.message.groovy.return.null", groovyScript);
}
if (!isScriptResultTrue(groovyResult)) {
error.add(groovyResult.toString());
}
}
@Override
public Type getType() {
return Type.GROOVY;
}
private boolean isScriptResultTrue(Object groovyResult) {
return groovyResult.equals(true) || groovyResult.toString().trim().toLowerCase().equals("true");
}
}

View File

@@ -0,0 +1,46 @@
/*
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 static org.apache.commons.validator.GenericValidator.isInt;
/**
* Checks if the value is an integer
*/
public class IntegerValidation extends EmptyValueIsValid {
@Override
public void check(int row, String value, ValidationError error) {
if (!isInt(value)) {
error.add("validation.message.integer");
}
}
@Override
public Type getType() {
return Type.INTEGER;
}
}

View File

@@ -0,0 +1,52 @@
/*
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 static org.apache.commons.validator.GenericValidator.maxLength;
/**
* Checks if the value is shorter or exactly as long as the given max length
*/
public class MaxLengthValidation extends EmptyValueIsValid {
private int maxLength;
public MaxLengthValidation(int maxLength) {
this.maxLength = maxLength;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!maxLength(value, maxLength)) {
error.add("validation.message.max.length", Integer.toString(maxLength));
}
}
@Override
public Type getType() {
return Type.MAX_LENGTH;
}
}

View File

@@ -0,0 +1,52 @@
/*
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 static org.apache.commons.validator.GenericValidator.minLength;
/**
* Checks if the value is at minimum long as the given min length
*/
public class MinLengthValidation extends EmptyValueIsValid {
private int minLength;
public MinLengthValidation(int minLength) {
this.minLength = minLength;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!minLength(value, minLength)) {
error.add("validation.message.min.length", Integer.toString(minLength));
}
}
@Override
public Type getType() {
return Type.MIN_LENGTH;
}
}

View File

@@ -0,0 +1,51 @@
/*
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 static org.apache.commons.validator.GenericValidator.isBlankOrNull;
/**
* Checks if the value is not empty
*/
public class NotEmptyValidation implements Validation {
@Override
public void check(int row, String value, ValidationError error) {
if (isBlankOrNull(value)) {
error.add("validation.message.not.empty");
}
}
@Override
public Type getType() {
return Type.NOT_EMPTY;
}
@Override
public boolean canBeChecked(String value) {
return true;
}
}

View File

@@ -0,0 +1,52 @@
/*
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 static org.apache.commons.validator.GenericValidator.matchRegexp;
/**
* Checks the value against the given reg exp
*/
public class RegExpValidation extends EmptyValueIsValid {
private String regexp;
public RegExpValidation(String regexp) {
this.regexp = regexp;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!matchRegexp(value, regexp)) {
error.add("validation.message.regexp", regexp);
}
}
@Override
public Type getType() {
return Type.REGEXP;
}
}

View File

@@ -0,0 +1,110 @@
/*
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 javafx.beans.property.ObjectProperty;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Service for running the validation async of the ui thread
*/
public class RevalidationService extends Service<List<ValidationError>> {
private static final Logger logger = LogManager.getLogger(RevalidationService.class);
private Validator validator;
private List<CSVRow> rows;
private String[] header;
public void setValidator(Validator validator) {
this.validator = validator;
}
public void setRows(List<CSVRow> rows) {
this.rows = rows;
}
public void setHeader(String[] header) {
this.header = header;
}
@Override
protected Task<List<ValidationError>> createTask() {
return new Task<List<ValidationError>>() {
@Override
protected List<ValidationError> call() throws Exception {
List<ValidationError> errors = new ArrayList<>();
try {
if (header != null) {
ValidationError headerError = validator.isHeaderValid(header);
if (headerError != null) {
logger.info("revalidate: header error found");
errors.add(headerError);
}
}
int maxRows = rows.size();
for (int lineNumber = 0; lineNumber < maxRows; lineNumber++) {
CSVRow row = rows.get(lineNumber);
Map<String, ObjectProperty<CSVValue>> table = row.getColumns();
Set<String> columns = table.keySet();
for (String column : columns) {
CSVValue value = table.get(column).getValue();
if (validator != null) {
ValidationError validationError = validator.isValid(lineNumber, column, value.getValue());
if (validationError != null) {
logger.info("revalidate: {} errors found in line {}", validationError.getMessages().size(), lineNumber);
errors.add(validationError);
value.setValidationError(validationError);
} else {
value.setValidationError(null);
}
} else {
value.setValidationError(null);
}
}
}
} catch (Throwable t) {
logger.error("validation error", t);
}
return errors;
}
};
}
}

View File

@@ -0,0 +1,78 @@
/*
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 ninja.javafx.smartcsv.fx.table.model.ColumnValueProvider;
import java.util.ArrayList;
import java.util.List;
import static java.util.Collections.sort;
import static java.util.stream.Collectors.joining;
/**
* Checks if the value is unique in the column
*/
public class UniqueValidation extends EmptyValueIsValid {
private ColumnValueProvider columnValueProvider;
private String column;
public UniqueValidation(ColumnValueProvider columnValueProvider, String column) {
this.columnValueProvider = columnValueProvider;
this.column = column;
}
@Override
public void check(int row, String value, ValidationError error) {
List<Integer> lineNumbers = new ArrayList<>();
int numberOfRows = columnValueProvider.getNumberOfRows();
for (int currentRowOfIteration = 0; currentRowOfIteration < numberOfRows; currentRowOfIteration++) {
String storedValue = columnValueProvider.getValue(currentRowOfIteration, column);
if (value.equals(storedValue) && currentRowOfIteration != row) {
lineNumbers.add(currentRowOfIteration + 1); // show not 0 based line numbers to user
}
}
if (!lineNumbers.isEmpty()) {
if (lineNumbers.size() > 1) {
sort(lineNumbers);
error.add("validation.message.uniqueness.multiple", value, lineNumbers.stream().map(Object::toString).collect(joining(", ")));
} else {
error.add("validation.message.uniqueness.single", value, lineNumbers.get(0).toString());
}
}
}
@Override
public Type getType() {
return Type.UNIQUE;
}
}

View File

@@ -0,0 +1,37 @@
/*
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;
/**
* Interface for all validations
*/
public interface Validation {
enum Type { NOT_EMPTY, UNIQUE, DOUBLE, INTEGER, MIN_LENGTH, MAX_LENGTH, DATE, ALPHANUMERIC, REGEXP, VALUE_OF, GROOVY }
void check(int row, String value, ValidationError error);
Type getType();
boolean canBeChecked(String value);
}

View File

@@ -52,7 +52,7 @@ public class ValidationConfiguration {
headerConfiguration.setNames(headerNames); headerConfiguration.setNames(headerNames);
} }
public Boolean getUniquenessRuleFor(String column) { public Boolean getUniqueRuleFor(String column) {
return (Boolean)getValue(column, "unique"); return (Boolean)getValue(column, "unique");
} }
@@ -73,32 +73,27 @@ public class ValidationConfiguration {
} }
public Integer getMaxLengthRuleFor(String column) { public Integer getMaxLengthRuleFor(String column) {
if (noRulesFor(column)) return null; Double value = (Double)getValue(column, "maxlength");
return doubleToInteger((Double)getValue(column, "maxlength")); return value != null ? doubleToInteger(value) : null;
} }
public String getDateRuleFor(String column) { public String getDateRuleFor(String column) {
if (noRulesFor(column)) return null;
return (String)getValue(column, "date"); return (String)getValue(column, "date");
} }
public Boolean getAlphanumericRuleFor(String column) { public Boolean getAlphanumericRuleFor(String column) {
if (noRulesFor(column)) return null;
return (Boolean)getValue(column, "alphanumeric"); return (Boolean)getValue(column, "alphanumeric");
} }
public String getRegexpRuleFor(String column) { public String getRegexpRuleFor(String column) {
if (noRulesFor(column)) return null;
return (String)getValue(column, "regexp"); return (String)getValue(column, "regexp");
} }
public List<String> getValueOfRuleFor(String column) { public List<String> getValueOfRuleFor(String column) {
if (noRulesFor(column)) return null;
return (List<String>)getValue(column, "value of"); return (List<String>)getValue(column, "value of");
} }
public String getGroovyRuleFor(String column) { public String getGroovyRuleFor(String column) {
if (noRulesFor(column)) return null;
return (String)getValue(column, "groovy"); return (String)getValue(column, "groovy");
} }
@@ -114,6 +109,11 @@ public class ValidationConfiguration {
setValue(column, value, "not empty"); setValue(column, value, "not empty");
} }
public void setUniqueRuleFor(String column, Boolean value) {
setValue(column, value, "unique");
}
public void setMinLengthRuleFor(String column, Integer value) { public void setMinLengthRuleFor(String column, Integer value) {
setValue(column, value == null ? null : value.doubleValue(), "minlength"); setValue(column, value == null ? null : value.doubleValue(), "minlength");
} }
@@ -155,18 +155,19 @@ public class ValidationConfiguration {
} }
private Object getValue(String column, String key) { private Object getValue(String column, String key) {
if (noRulesFor(column)) return null; if (columnConfigurations != null) {
Map rulesForColumn = columnConfigurations.get(column);
if (rulesForColumn != null) {
return columnConfigurations.get(column).get(key); return columnConfigurations.get(column).get(key);
} }
}
return null;
}
private boolean noHeader() { private boolean noHeader() {
return headerConfiguration == null; return headerConfiguration == null;
} }
private boolean noRulesFor(String column) {
return columnConfigurations == null || columnConfigurations.get(column) == null;
}
private Integer doubleToInteger(Double value) { private Integer doubleToInteger(Double value) {
if (value == null) return null; if (value == null) return null;
return (int)Math.round(value); return (int)Math.round(value);

View File

@@ -38,6 +38,7 @@ public class ValidationError {
private List<ValidationMessage> messages = new ArrayList<>(); private List<ValidationMessage> messages = new ArrayList<>();
private Integer lineNumber; private Integer lineNumber;
private String column = "";
private ValidationError(Integer lineNumber) { private ValidationError(Integer lineNumber) {
this.lineNumber = lineNumber; this.lineNumber = lineNumber;
@@ -51,10 +52,19 @@ public class ValidationError {
return new ValidationError(-1); return new ValidationError(-1);
} }
public ValidationError column(String column) {
this.column = column;
return this;
}
public Integer getLineNumber() { public Integer getLineNumber() {
return lineNumber; return lineNumber;
} }
public String getColumn() {
return column;
}
public List<ValidationMessage> getMessages() { public List<ValidationMessage> getMessages() {
return messages; return messages;
} }

View File

@@ -28,7 +28,6 @@ package ninja.javafx.smartcsv.validation;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileReader; import ninja.javafx.smartcsv.FileReader;
import org.springframework.stereotype.Service;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;

View File

@@ -29,7 +29,6 @@ package ninja.javafx.smartcsv.validation;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileWriter; import ninja.javafx.smartcsv.FileWriter;
import org.springframework.stereotype.Service;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;

View File

@@ -26,19 +26,12 @@
package ninja.javafx.smartcsv.validation; package ninja.javafx.smartcsv.validation;
import groovy.lang.Binding; import ninja.javafx.smartcsv.fx.table.model.ColumnValueProvider;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import org.codehaus.groovy.control.CompilationFailedException;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static java.util.stream.Collectors.joining;
import static org.apache.commons.validator.GenericValidator.*;
/** /**
* This class checks all the validations defined in the * This class checks all the validations defined in the
* Config against a given value * Config against a given value
@@ -50,9 +43,8 @@ public class Validator {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private ValidationConfiguration validationConfig; private ValidationConfiguration validationConfig;
private GroovyShell shell = new GroovyShell(); private ColumnValueProvider columnValueProvider;
private Map<String, Script> scriptCache = new HashMap<>(); private Map<String, Map<Validation.Type, Validation>> columnValidationMap = new HashMap<>();
private Map<String, HashMap<String, Integer>> uniquenessLookupTable = new HashMap<>();
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constructors // constructors
@@ -60,10 +52,13 @@ public class Validator {
/** /**
* JSON configuration for this validator * JSON configuration for this validator
*
* @param validationConfig * @param validationConfig
*/ */
public Validator(ValidationConfiguration validationConfig) { public Validator(ValidationConfiguration validationConfig, ColumnValueProvider columnValueProvider) {
this.validationConfig = validationConfig; this.validationConfig = validationConfig;
this.columnValueProvider = columnValueProvider;
initColumnValidations();
} }
@@ -71,31 +66,35 @@ public class Validator {
// public methods // public methods
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public boolean needsColumnValidation(String column) {
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap != null) {
return validationMap.containsKey(Validation.Type.UNIQUE);
}
return false;
}
/** /**
* checks if the value is valid for the column configuration * checks if the value is valid for the column configuration
*
* @param column the column name * @param column the column name
* @param value the value to check * @param value the value to check
* @return ValidationError with information if valid and if not which getMessage happened * @return ValidationError with information if valid and if not which getMessage happened
*/ */
public ValidationError isValid(String column, String value, Integer lineNumber) { public ValidationError isValid(Integer row, String column, String value) {
ValidationError result = null; ValidationError result = null;
if (hasConfig()) { if (hasConfig()) {
ValidationError error = ValidationError.withLineNumber(row).column(column);
ValidationError error = ValidationError.withLineNumber(lineNumber); Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
checkBlankOrNull(column, value, error); if (validationMap != null) {
if (value != null && !value.isEmpty()) { for (Validation validation: validationMap.values()) {
checkRegularExpression(column, value, error); if (validation.canBeChecked(value)) {
checkAlphaNumeric(column, value, error); validation.check(row, 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);
checkUniqueness(column, value, lineNumber, error);
} }
if (!error.isEmpty()) { if (!error.isEmpty()) {
result = error; result = error;
} }
@@ -103,151 +102,102 @@ public class Validator {
return result; return result;
} }
public boolean hasConfig() { public boolean hasConfig() {
return validationConfig != null; return validationConfig != null;
} }
public void reinitializeColumn(String column) {
clear(column);
initializeColumnWithRules(column);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// private methods // private methods
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void checkUniqueness(String column, String value, Integer lineNumber, ValidationError error) { private void add(String column, Validation validation) {
if (validationConfig.getUniquenessRuleFor(column) != null && validationConfig.getUniquenessRuleFor(column)) { Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
HashMap<String, Integer> columnValueMap = uniquenessLookupTable.get(column); if (validationMap == null) {
columnValueMap = getColumnValueMap(column, columnValueMap); validationMap = new HashMap<>();
Integer valueInLineNumber = columnValueMap.get(value); columnValidationMap.put(column, validationMap);
if (valueInLineNumber != null) {
if (!valueInLineNumber.equals(lineNumber)) {
error.add("validation.message.uniqueness", value, valueInLineNumber.toString());
} }
} else { validationMap.put(validation.getType(), validation);
columnValueMap.put(value, lineNumber); }
private void clear(String column) {
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap != null) {
validationMap.clear();
}
}
private void initColumnValidations() {
if (hasConfig()) {
String[] columns = validationConfig.headerNames();
for (String column : columns) {
initializeColumnWithRules(column);
} }
} }
} }
private HashMap<String, Integer> getColumnValueMap(String column, HashMap<String, Integer> valueLineNumber) { private void initializeColumnWithRules(String column) {
if (valueLineNumber == null) { Boolean alphaNumeric = validationConfig.getAlphanumericRuleFor(column);
valueLineNumber = new HashMap<>(); if (alphaNumeric != null && alphaNumeric) {
uniquenessLookupTable.put(column, valueLineNumber); add(column, new AlphaNumericValidation());
}
return valueLineNumber;
} }
private void checkGroovy(String column, String value, ValidationError error) { Boolean doubleRule = validationConfig.getDoubleRuleFor(column);
String groovyScript = validationConfig.getGroovyRuleFor(column); if (doubleRule != null && doubleRule) {
if (groovyScript != null) { add(column, new DoubleValidation());
Script script = scriptCache.get(column);
if (script == null) {
script = shell.parse(groovyScript);
scriptCache.put(column, script);
} }
Binding binding = new Binding(); Boolean integerRule = validationConfig.getIntegerRuleFor(column);
binding.setVariable("value", value); if (integerRule != null && integerRule) {
script.setBinding(binding); add(column, new IntegerValidation());
Object groovyResult = null;
try {
groovyResult = script.run();
} catch (CompilationFailedException e) {
error.add("validation.message.groovy.exception", groovyScript, e.getMessage());
e.printStackTrace();
}
if (groovyResult == null) {
error.add("validation.message.groovy.return.null", groovyScript);
} }
if (!isScriptResultTrue(groovyResult)) { Boolean notEmptyRule = validationConfig.getNotEmptyRuleFor(column);
error.add(groovyResult.toString()); if (notEmptyRule != null && notEmptyRule) {
add(column, new NotEmptyValidation());
} }
} Boolean uniqueRule = validationConfig.getUniqueRuleFor(column);
if (uniqueRule != null && uniqueRule) {
add(column, new UniqueValidation(columnValueProvider, column));
} }
private boolean isScriptResultTrue(Object groovyResult) { String dateRule = validationConfig.getDateRuleFor(column);
return groovyResult.equals(true) || groovyResult.toString().trim().toLowerCase().equals("true"); if (dateRule != null && !dateRule.trim().isEmpty()) {
add(column, new DateValidation(dateRule));
} }
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(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(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(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(String column, String value, ValidationError error) {
Integer minLength = validationConfig.getMinLengthRuleFor(column); Integer minLength = validationConfig.getMinLengthRuleFor(column);
if (minLength != null) { if (minLength != null) {
if (!minLength(value, minLength)) { add(column, new MinLengthValidation(minLength));
error.add("validation.message.min.length", minLength.toString());
}
}
} }
private void checkMaxLength(String column, String value, ValidationError error) {
Integer maxLength = validationConfig.getMaxLengthRuleFor(column); Integer maxLength = validationConfig.getMaxLengthRuleFor(column);
if (maxLength != null) { if (maxLength != null) {
if (!maxLength(value, maxLength)) { add(column, new MaxLengthValidation(maxLength));
error.add("validation.message.max.length", maxLength.toString());
}
}
} }
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);
}
}
}
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(String column, String value, ValidationError error) {
String regexp = validationConfig.getRegexpRuleFor(column); String regexp = validationConfig.getRegexpRuleFor(column);
if (regexp != null && !regexp.trim().isEmpty()) { if (regexp != null && !regexp.trim().isEmpty()) {
if (!matchRegexp(value, regexp)) { add(column, new RegExpValidation(regexp));
error.add("validation.message.regexp", regexp); }
}
String groovy = validationConfig.getGroovyRuleFor(column);
if (groovy != null && !groovy.trim().isEmpty()) {
add(column, new GroovyValidation(groovy));
}
List<String> valueOfRule = validationConfig.getValueOfRuleFor(column);
if (valueOfRule != null && !valueOfRule.isEmpty()) {
add(column, new ValueOfValidation(valueOfRule));
} }
} }
public ValidationError isHeaderValid(String[] headerNames) { public ValidationError isHeaderValid(String[] headerNames) {
ValidationError result = null; ValidationError result = null;
if (validationConfig != null) { if (validationConfig != null) {
@@ -262,7 +212,7 @@ public class Validator {
ValidationError error = ValidationError.withoutLineNumber(); ValidationError error = ValidationError.withoutLineNumber();
for(int i=0; i<headerNamesConfig.length; i++) { for (int i = 0; i < headerNamesConfig.length; i++) {
if (!headerNamesConfig[i].equals(headerNames[i])) { if (!headerNamesConfig[i].equals(headerNames[i])) {
error.add("validation.message.header.match", error.add("validation.message.header.match",
Integer.toString(i), Integer.toString(i),
@@ -277,8 +227,4 @@ public class Validator {
} }
return result; return result;
} }
public void clearScriptCache() {
scriptCache.clear();
}
} }

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 java.util.List;
import static java.util.stream.Collectors.joining;
/**
* Checks if the value is part of a list of values
*/
public class ValueOfValidation extends EmptyValueIsValid {
private List<String> values;
public ValueOfValidation(List<String> values) {
this.values = values;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!values.contains(value)) {
String commaSeparated = values.stream().collect(joining(", "));
error.add("validation.message.value.of", value, commaSeparated);
}
}
@Override
public Type getType() {
return Type.VALUE_OF;
}
}

View File

@@ -1,16 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.*?>
<?import javafx.scene.control.Hyperlink?> <?import javafx.scene.control.*?>
<?import javafx.scene.control.Label?> <?import javafx.scene.layout.*?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="600.0" spacing="4.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1"> <VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="600.0" spacing="4.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1">
<children> <children>
<Label text="SmartCSV.fx"> <Label text="SmartCSV.fx">

View File

@@ -1,5 +1,5 @@
application.name = SmartCSV.fx application.name = SmartCSV.fx
application.version = 0.5 application.version = 0.7
# fxml views # fxml views
fxml.smartcvs.view = /ninja/javafx/smartcsv/fx/smartcsv.fxml fxml.smartcvs.view = /ninja/javafx/smartcsv/fx/smartcsv.fxml

View File

@@ -1,10 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<GridPane hgap="8.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" vgap="8.0" xmlns="http://javafx.com/javafx/8.0.66" xmlns:fx="http://javafx.com/fxml/1"> <GridPane hgap="8.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" vgap="8.0" xmlns="http://javafx.com/javafx/8.0.66" xmlns:fx="http://javafx.com/fxml/1">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />

View File

@@ -82,9 +82,14 @@
.goto-icon { .goto-icon {
-glyph-name: "SUBDIRECTORY_ARROW_RIGHT"; -glyph-name: "SUBDIRECTORY_ARROW_RIGHT";
-glyph-size: 16px; -glyph-size: 16px;
} }
.export-icon {
-glyph-name: "BUG";
-glyph-size: 16px;
}
/* toolbar customization based on http://fxexperience.com/2012/02/customized-segmented-toolbar-buttons/ */ /* toolbar customization based on http://fxexperience.com/2012/02/customized-segmented-toolbar-buttons/ */
#background { #background {
@@ -149,6 +154,11 @@
-fx-fill: white; -fx-fill: white;
} }
.tool-bar .export-icon {
-glyph-size: 16px;
-fx-fill: white;
}
.segmented-button-bar .button { .segmented-button-bar .button {
-fx-background-color: -fx-background-color:
-darkest-black, -darkest-black,

View File

@@ -1,27 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import de.jensd.fx.glyphs.GlyphsStack?> <?import de.jensd.fx.glyphs.*?>
<?import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIconView?> <?import de.jensd.fx.glyphs.materialdesignicons.*?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?> <?import javafx.scene.control.*?>
<?import javafx.scene.control.Label?> <?import javafx.scene.layout.*?>
<?import javafx.scene.control.Menu?> <?import java.net.URL?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.SeparatorMenuItem?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.control.Tooltip?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<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.101" xmlns:fx="http://javafx.com/fxml/1"> <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.101" xmlns:fx="http://javafx.com/fxml/1">
<top> <top>
<VBox id="background" prefWidth="100.0" BorderPane.alignment="CENTER"> <VBox id="background" prefWidth="100.0" BorderPane.alignment="CENTER">
@@ -94,6 +78,11 @@
<MaterialDesignIconView styleClass="preferences-icon" /> <MaterialDesignIconView styleClass="preferences-icon" />
</graphic> </graphic>
</MenuItem> </MenuItem>
<MenuItem fx:id="exportMenuItem" disable="true" mnemonicParsing="false" onAction="#export" text="%menu.export">
<graphic>
<MaterialDesignIconView styleClass="export-icon" />
</graphic>
</MenuItem>
<SeparatorMenuItem mnemonicParsing="false" /> <SeparatorMenuItem mnemonicParsing="false" />
<MenuItem mnemonicParsing="false" onAction="#close" text="%menu.close"> <MenuItem mnemonicParsing="false" onAction="#close" text="%menu.close">
<graphic> <graphic>
@@ -245,6 +234,14 @@
<MaterialDesignIconView styleClass="preferences-icon" /> <MaterialDesignIconView styleClass="preferences-icon" />
</graphic> </graphic>
</Button> </Button>
<Button fx:id="exportButton" disable="true" mnemonicParsing="false" onAction="#export">
<tooltip>
<Tooltip text="%menu.export" />
</tooltip>
<graphic>
<MaterialDesignIconView styleClass="export-icon" />
</graphic>
</Button>
<Button mnemonicParsing="false" onAction="#close" styleClass="last"> <Button mnemonicParsing="false" onAction="#close" styleClass="last">
<tooltip> <tooltip>
<Tooltip text="%menu.close" /> <Tooltip text="%menu.close" />

View File

@@ -14,6 +14,7 @@ menu.preferences = Preferences
menu.delete.row = Delete row menu.delete.row = Delete row
menu.add.row = Add row menu.add.row = Add row
menu.goto.line = Goto line menu.goto.line = Goto line
menu.export = Export error log
title.validation.errors = Validation Errors: title.validation.errors = Validation Errors:
@@ -52,7 +53,8 @@ validation.message.min.length = has not min length of {0}
validation.message.max.length = has not max length of {0} validation.message.max.length = has not max length of {0}
validation.message.date.format = is not a date of format {0} validation.message.date.format = is not a date of format {0}
validation.message.regexp = does not match {0} validation.message.regexp = does not match {0}
validation.message.uniqueness = value {0} is not unique (found in line {1}) validation.message.uniqueness.multiple = value {0} is not unique (found in rows {1})
validation.message.uniqueness.single = value {0} is not unique (found in row {1})
validation.message.header.length = number of headers is not correct! there are {0} but there should be {1} 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 "{2}" validation.message.header.match = header number {0} does not match "{1}" should be "{2}"
@@ -71,9 +73,15 @@ validation.rule.label.groovy = groovy:
validation.rules.active = active validation.rules.active = active
validation.rules.name = rule validation.rules.name = rule
validation.rules.value = value validation.rules.value = value
validation.rule.label.unique = Unique in column:
dialog.validation.rules.title = Validation rules dialog.validation.rules.title = Validation rules
dialog.validation.rules.header = Validation rules of column "{0}" dialog.validation.rules.header = Validation rules of column "{0}"
context.menu.edit.column.rules = Edit rules context.menu.edit.column.rules = Edit rules
lineNumber = Selected line: lineNumber = Selected line:
log.header.message = {0} has {1} errors
log.message = row {0} column {1} : {2}
column = column

View File

@@ -23,6 +23,7 @@ menu.preferences = Einstellungen
menu.delete.row = Zeile l\u00f6schen menu.delete.row = Zeile l\u00f6schen
menu.add.row = Zeile hinzuf\u00fcgen menu.add.row = Zeile hinzuf\u00fcgen
menu.goto.line = Springe zur Zeile menu.goto.line = Springe zur Zeile
menu.export = Export Fehlerdatei
title.validation.errors = Fehler in der Datei: title.validation.errors = Fehler in der Datei:
@@ -61,7 +62,8 @@ validation.message.min.length = Hat nicht die minimale L\u00e4nge von {0}
validation.message.max.length = Hat nicht die maximale L\u00e4nge von {0} validation.message.max.length = Hat nicht die maximale L\u00e4nge von {0}
validation.message.date.format = Das Datumsformat entspricht nicht {0} validation.message.date.format = Das Datumsformat entspricht nicht {0}
validation.message.regexp = entspricht nicht dem regul\u00e4ren Ausdruck {0} validation.message.regexp = entspricht nicht dem regul\u00e4ren Ausdruck {0}
validation.message.uniqueness = Wert {0} ist nicht einmalig (gefunden in Zeile {1}) validation.message.uniqueness.multiple = Wert {0} ist nicht einmalig (gefunden in den Zeilen {1})
validation.message.uniqueness.single = Wert {0} ist nicht einmalig (gefunden in Zeile {1})
validation.message.header.length = Anzahl der \u00dcberschriften ist nicht korrekt! Es sind {0} aber es sollten {1} sein 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.header.match = \u00dcberschrift in Spalte {0} stimmt nicht. "{1}" sollte "{3}" sein
@@ -80,6 +82,7 @@ validation.rule.label.groovy = groovy:
validation.rules.active = Aktiv validation.rules.active = Aktiv
validation.rules.name = Regel validation.rules.name = Regel
validation.rules.value = Wert validation.rules.value = Wert
validation.rule.label.unique = Einmalig in Spalte:
dialog.validation.rules.title = Pr\u00fcfregeln dialog.validation.rules.title = Pr\u00fcfregeln
dialog.validation.rules.header = Pr\u00fcfregeln f\u00fcr die Spalte "{0}" dialog.validation.rules.header = Pr\u00fcfregeln f\u00fcr die Spalte "{0}"
@@ -87,3 +90,8 @@ dialog.validation.rules.header = Pr\u00fcfregeln f\u00fcr die Spalte "{0}"
context.menu.edit.column.rules = Pr\u00fcfregeln bearbeiten context.menu.edit.column.rules = Pr\u00fcfregeln bearbeiten
lineNumber = Ausgew\u00e4hlte Zeile: lineNumber = Ausgew\u00e4hlte Zeile:
log.header.message = {0} hat {1} Fehler
log.message = Zeile {0} Spalte {1} : {2}
column = Spalte

View File

@@ -1,15 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.CheckBox?> <?import javafx.scene.control.*?>
<?import javafx.scene.control.Label?> <?import javafx.scene.layout.*?>
<?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?>
<?import org.fxmisc.richtext.CodeArea?> <?import org.fxmisc.richtext.CodeArea?>
<?import java.net.URL?> <?import java.net.URL?>
<GridPane hgap="10.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="600.0" vgap="10.0" xmlns="http://javafx.com/javafx/8.0.101" xmlns:fx="http://javafx.com/fxml/1"> <GridPane hgap="10.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="600.0" vgap="10.0" xmlns="http://javafx.com/javafx/8.0.101" xmlns:fx="http://javafx.com/fxml/1">
@@ -31,41 +24,46 @@
<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> </rowConstraints>
<children> <children>
<Label text="%validation.rule.label.not_empty" GridPane.columnIndex="1" GridPane.rowIndex="1" /> <Label text="%validation.rule.label.not_empty" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="%validation.rule.label.integer" GridPane.columnIndex="1" GridPane.rowIndex="2" /> <Label text="%validation.rule.label.integer" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Label text="%validation.rule.label.double" GridPane.columnIndex="1" GridPane.rowIndex="3" /> <Label text="%validation.rule.label.double" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<Label text="%validation.rule.label.minlength" GridPane.columnIndex="1" GridPane.rowIndex="5" /> <Label text="%validation.rule.label.minlength" GridPane.columnIndex="1" GridPane.rowIndex="6" />
<Label text="%validation.rule.label.maxlength" GridPane.columnIndex="1" GridPane.rowIndex="6" /> <Label text="%validation.rule.label.maxlength" GridPane.columnIndex="1" GridPane.rowIndex="7" />
<Label text="%validation.rule.label.dateformat" GridPane.columnIndex="1" GridPane.rowIndex="7" /> <Label text="%validation.rule.label.dateformat" GridPane.columnIndex="1" GridPane.rowIndex="8" />
<Label text="%validation.rule.label.alphanumeric" GridPane.columnIndex="1" GridPane.rowIndex="4" /> <Label text="%validation.rule.label.alphanumeric" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<Label text="%validation.rule.label.regexp" GridPane.columnIndex="1" GridPane.rowIndex="8" /> <Label text="%validation.rule.label.regexp" GridPane.columnIndex="1" GridPane.rowIndex="9" />
<Label text="%validation.rule.label.value_of" GridPane.columnIndex="1" GridPane.rowIndex="9" /> <Label text="%validation.rule.label.value_of" GridPane.columnIndex="1" GridPane.rowIndex="10" />
<Label text="%validation.rule.label.groovy" GridPane.columnIndex="1" GridPane.rowIndex="10" /> <Label text="%validation.rule.label.groovy" GridPane.columnIndex="1" GridPane.rowIndex="11" />
<CheckBox fx:id="notEmptyRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="1" /> <Label text="%validation.rule.label.unique" GridPane.columnIndex="1" GridPane.rowIndex="5" />
<CheckBox fx:id="integerRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="2" />
<CheckBox fx:id="doublerRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="3" />
<CheckBox fx:id="alphanumericRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="4" />
<Spinner fx:id="minLengthSpinner" GridPane.columnIndex="2" GridPane.rowIndex="5" />
<Spinner fx:id="maxLengthSpinner" GridPane.columnIndex="2" GridPane.rowIndex="6" />
<TextField fx:id="dateformatRuleTextField" GridPane.columnIndex="2" GridPane.rowIndex="7" />
<TextField fx:id="regexpRuleTextField" GridPane.columnIndex="2" GridPane.rowIndex="8" />
<TextField fx:id="valueOfRuleTextField" GridPane.columnIndex="2" GridPane.rowIndex="9" />
<CodeArea fx:id="groovyRuleTextArea" prefHeight="300.0" prefWidth="200.0" GridPane.columnIndex="2" GridPane.rowIndex="10" GridPane.rowSpan="2" />
<CheckBox fx:id="enableNotEmptyRule" mnemonicParsing="false" GridPane.rowIndex="1" /> <CheckBox fx:id="enableNotEmptyRule" mnemonicParsing="false" GridPane.rowIndex="1" />
<CheckBox fx:id="notEmptyRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="1" />
<CheckBox fx:id="enableIntegerRule" mnemonicParsing="false" GridPane.rowIndex="2" /> <CheckBox fx:id="enableIntegerRule" mnemonicParsing="false" GridPane.rowIndex="2" />
<CheckBox fx:id="integerRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="2" />
<CheckBox fx:id="enableDoubleRule" mnemonicParsing="false" GridPane.rowIndex="3" /> <CheckBox fx:id="enableDoubleRule" mnemonicParsing="false" GridPane.rowIndex="3" />
<CheckBox fx:id="doublerRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="3" />
<CheckBox fx:id="enableAlphanumericRule" mnemonicParsing="false" GridPane.rowIndex="4" /> <CheckBox fx:id="enableAlphanumericRule" mnemonicParsing="false" GridPane.rowIndex="4" />
<CheckBox fx:id="enableMinLengthRule" mnemonicParsing="false" GridPane.rowIndex="5" /> <CheckBox fx:id="alphanumericRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="4" />
<CheckBox fx:id="enableMaxLengthRule" mnemonicParsing="false" GridPane.rowIndex="6" /> <CheckBox fx:id="enableUniqueRule" mnemonicParsing="false" GridPane.rowIndex="5" />
<CheckBox fx:id="enableDateRule" mnemonicParsing="false" GridPane.rowIndex="7" /> <CheckBox fx:id="uniqueRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="5" />
<CheckBox fx:id="enableRegexpRule" mnemonicParsing="false" GridPane.rowIndex="8" /> <CheckBox fx:id="enableMinLengthRule" mnemonicParsing="false" GridPane.rowIndex="6" />
<CheckBox fx:id="enableValueOfRule" mnemonicParsing="false" GridPane.rowIndex="9" /> <Spinner fx:id="minLengthSpinner" GridPane.columnIndex="2" GridPane.rowIndex="6" />
<CheckBox fx:id="enableGroovyRule" mnemonicParsing="false" GridPane.rowIndex="10" /> <CheckBox fx:id="enableMaxLengthRule" mnemonicParsing="false" GridPane.rowIndex="7" />
<Spinner fx:id="maxLengthSpinner" GridPane.columnIndex="2" GridPane.rowIndex="7" />
<CheckBox fx:id="enableDateRule" mnemonicParsing="false" GridPane.rowIndex="8" />
<TextField fx:id="dateformatRuleTextField" GridPane.columnIndex="2" GridPane.rowIndex="8" />
<CheckBox fx:id="enableRegexpRule" mnemonicParsing="false" GridPane.rowIndex="9" />
<TextField fx:id="regexpRuleTextField" GridPane.columnIndex="2" GridPane.rowIndex="9" />
<CheckBox fx:id="enableValueOfRule" mnemonicParsing="false" GridPane.rowIndex="10" />
<TextField fx:id="valueOfRuleTextField" GridPane.columnIndex="2" GridPane.rowIndex="10" />
<CheckBox fx:id="enableGroovyRule" mnemonicParsing="false" GridPane.rowIndex="11" />
<CodeArea fx:id="groovyRuleTextArea" prefHeight="300.0" prefWidth="200.0" GridPane.columnIndex="2" GridPane.rowIndex="11" GridPane.rowSpan="2" />
<Label style="-fx-font-weight: bold;" text="%validation.rules.active" /> <Label style="-fx-font-weight: bold;" text="%validation.rules.active" />
<Label style="-fx-font-weight: bold;" text="%validation.rules.name" GridPane.columnIndex="1" /> <Label style="-fx-font-weight: bold;" text="%validation.rules.name" GridPane.columnIndex="1" />
<Label style="-fx-font-weight: bold;" text="%validation.rules.value" GridPane.columnIndex="2" /> <Label style="-fx-font-weight: bold;" text="%validation.rules.value" GridPane.columnIndex="2" />
</children> </children>
<padding> <padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" /> <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />

View File

@@ -26,13 +26,10 @@
package ninja.javafx.smartcsv.fx.table.model; package ninja.javafx.smartcsv.fx.table.model;
import ninja.javafx.smartcsv.validation.ValidationConfiguration;
import ninja.javafx.smartcsv.validation.Validator;
import org.junit.Test; import org.junit.Test;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;
/** /**
* unit test for the csv model * unit test for the csv model

View File

@@ -1,13 +1,10 @@
package ninja.javafx.smartcsv.fx.table.model; package ninja.javafx.smartcsv.fx.table.model;
import ninja.javafx.smartcsv.validation.Validator;
import org.hamcrest.Matchers;
import org.junit.Test; import org.junit.Test;
import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*; import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
/** /**
* unit test for row class * unit test for row class

View File

@@ -1,60 +0,0 @@
package ninja.javafx.smartcsv.fx.table.model;
import ninja.javafx.smartcsv.validation.Validator;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* unit test for the value class
*/
public class CSVValueTest {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constants
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static final String COLUMN = "COLUMN";
static final String VALUE = "VALUE";
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// mocks
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Validator validator = mock(Validator.class);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// subject under test
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CSVValue sut;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// init
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Before
public void initialize() {
sut = new CSVValue();
sut.setValidator(validator);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Test
public void set_value_calls_validation() {
//setup
sut.setColumn(COLUMN);
// execution
sut.setValue(VALUE);
// assertion
verify(validator).isValid(eq(COLUMN), eq(VALUE), anyInt());
}
}

View File

@@ -70,8 +70,10 @@ public class ValidatorTest {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Test @Test
public void validation() { public void validation() {
System.out.println(column + " " + value + " " + expectedResult + " " + expectedError);
// execution // execution
ValidationError result = sut.isValid(column, value, 0); ValidationError result = sut.isValid(0, column, value);
// assertion // assertion
assertThat(result == null, is(expectedResult)); assertThat(result == null, is(expectedResult));
@@ -112,7 +114,7 @@ public class ValidatorTest {
} }
public static String json(String column, String rule, Object value) { public static String json(String column, String rule, Object value) {
String json = "{\"columns\":{\"" + column + "\":{\"" + rule + "\":"; String json = "{\"headers\": { \"list\": [\""+column+"\"]},\"columns\":{\"" + column + "\":{\"" + rule + "\":";
if (value instanceof String) { if (value instanceof String) {
json += "\""+ value + "\""; json += "\""+ value + "\"";
} else if (value instanceof List) { } else if (value instanceof List) {