diff --git a/src/main/java/ninja/javafx/smartcsv/fx/table/model/CSVModel.java b/src/main/java/ninja/javafx/smartcsv/fx/table/model/CSVModel.java index 8dce7da..9f15502 100644 --- a/src/main/java/ninja/javafx/smartcsv/fx/table/model/CSVModel.java +++ b/src/main/java/ninja/javafx/smartcsv/fx/table/model/CSVModel.java @@ -39,7 +39,7 @@ import org.apache.logging.log4j.Logger; * The CSVModel is the client representation for the csv filepath. * It holds the data in rows, stores the header and manages the validator. */ -public final class CSVModel { +public final class CSVModel implements ColumnValueProvider { private static final Logger logger = LogManager.getLogger(CSVModel.class); @@ -55,7 +55,7 @@ public final class CSVModel { * @param validationConfiguration the validator configuration for this data */ public void setValidationConfiguration(ValidationConfiguration validationConfiguration) { - this.validator = new Validator(validationConfiguration); + this.validator = new Validator(validationConfiguration, this); revalidate(); } @@ -145,11 +145,19 @@ public final class CSVModel { public ValidationConfiguration createValidationConfiguration() { ValidationConfiguration newValidationConfiguration = new ValidationConfiguration(); newValidationConfiguration.setHeaderNames(this.header); - this.validator = new Validator(newValidationConfiguration); + this.validator = new Validator(newValidationConfiguration, this); this.revalidate(); return newValidationConfiguration; } + @Override + public String getValue(int row, String column) { + return rows.get(row).getColumns().get(column).getValue().getValue(); + } + @Override + public int getNumberOfRows() { + return rows.size(); + } } diff --git a/src/main/java/ninja/javafx/smartcsv/fx/table/model/ColumnValueProvider.java b/src/main/java/ninja/javafx/smartcsv/fx/table/model/ColumnValueProvider.java new file mode 100644 index 0000000..816e614 --- /dev/null +++ b/src/main/java/ninja/javafx/smartcsv/fx/table/model/ColumnValueProvider.java @@ -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(); + +} diff --git a/src/main/java/ninja/javafx/smartcsv/validation/UniqueValidation.java b/src/main/java/ninja/javafx/smartcsv/validation/UniqueValidation.java index 10c4f24..ca9d208 100644 --- a/src/main/java/ninja/javafx/smartcsv/validation/UniqueValidation.java +++ b/src/main/java/ninja/javafx/smartcsv/validation/UniqueValidation.java @@ -25,26 +25,50 @@ */ package ninja.javafx.smartcsv.validation; -import java.util.HashMap; +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 EmptyAllowedValidation { - private HashMap columnValueMap = new HashMap<>(); + 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) { - Integer valueInLineNumber = columnValueMap.get(value); - if (valueInLineNumber != null) { - if (!valueInLineNumber.equals(row)) { - valueInLineNumber += 1; // show not 0 based line numbers to user - error.add("validation.message.uniqueness", value, valueInLineNumber.toString()); + + List lineNumbers = new ArrayList<>(); + + int numberOfRows = columnValueProvider.getNumberOfRows(); + for (int currentRowOfIteration = 0; currentRowOfIteration < numberOfRows; currentRowOfIteration++) { + String storedValue = columnValueProvider.getValue(currentRowOfIteration, column); + + if (storedValue.equals(value) && currentRowOfIteration != row) { + lineNumbers.add(currentRowOfIteration + 1); // show not 0 based line numbers to user } - } else { - columnValueMap.put(value, row); } + + 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 diff --git a/src/main/java/ninja/javafx/smartcsv/validation/Validator.java b/src/main/java/ninja/javafx/smartcsv/validation/Validator.java index 4a94f5f..bc5fea9 100644 --- a/src/main/java/ninja/javafx/smartcsv/validation/Validator.java +++ b/src/main/java/ninja/javafx/smartcsv/validation/Validator.java @@ -26,6 +26,8 @@ package ninja.javafx.smartcsv.validation; +import ninja.javafx.smartcsv.fx.table.model.ColumnValueProvider; + import java.util.HashMap; import java.util.List; import java.util.Map; @@ -41,6 +43,7 @@ public class Validator { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private ValidationConfiguration validationConfig; + private ColumnValueProvider columnValueProvider; private Map> columnValidationMap = new HashMap<>(); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -52,8 +55,9 @@ public class Validator { * * @param validationConfig */ - public Validator(ValidationConfiguration validationConfig) { + public Validator(ValidationConfiguration validationConfig, ColumnValueProvider columnValueProvider) { this.validationConfig = validationConfig; + this.columnValueProvider = columnValueProvider; initColumnValidations(); } @@ -160,7 +164,7 @@ public class Validator { Boolean uniqueRule = validationConfig.getUniqueRuleFor(column); if (uniqueRule != null && uniqueRule) { - add(column, new UniqueValidation()); + add(column, new UniqueValidation(columnValueProvider, column)); } String dateRule = validationConfig.getDateRuleFor(column); diff --git a/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.properties b/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.properties index b47010a..1e938c5 100644 --- a/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.properties +++ b/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv.properties @@ -52,7 +52,8 @@ validation.message.min.length = has not min 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.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.match = header number {0} does not match "{1}" should be "{2}" diff --git a/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv_de.properties b/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv_de.properties index a13561b..fda8c6d 100644 --- a/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv_de.properties +++ b/src/main/resources/ninja/javafx/smartcsv/fx/smartcsv_de.properties @@ -61,7 +61,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.date.format = Das Datumsformat entspricht nicht {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.match = \u00dcberschrift in Spalte {0} stimmt nicht. "{1}" sollte "{3}" sein