mirror of
https://github.com/frosch95/SmartCSV.fx.git
synced 2026-04-11 13:38:23 +02:00
Compare commits
97 Commits
version_0_
...
0.9.2
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ce9ae8edd | |||
| 7c12b7506f | |||
| 6fc62006fa | |||
| fdc4f99fd5 | |||
| e29d60b9b8 | |||
| 0a4e86c160 | |||
| c07dde8e19 | |||
| 9b0e3707b7 | |||
| a1f6c24bae | |||
| c1a671504e | |||
| 7c3f140491 | |||
| 16373a033a | |||
| e9e71b5474 | |||
| 48c657b648 | |||
| 8bd90b47e1 | |||
| 44f36759a6 | |||
|
|
326e4d954b | ||
|
|
96446e4e75 | ||
|
|
5eaf021632 | ||
|
|
ef376d6c61 | ||
|
|
2676b523d3 | ||
|
|
7e34ff8c59 | ||
|
|
a37a84bd09 | ||
|
|
5100c668ab | ||
|
|
90bda028ec | ||
|
|
5e31f834ac | ||
|
|
d689423c61 | ||
|
|
9e8d71ca1d | ||
|
|
70855e614a | ||
| 4354afdf1d | |||
| 4002219dfe | |||
| 7723906935 | |||
| 5694273c51 | |||
| 04a54da798 | |||
| 6f635f5e75 | |||
| 742f129ea9 | |||
| 0c391e292e | |||
| cd0ca0ed11 | |||
| e799f0ac45 | |||
| 3664a4e8a7 | |||
| e87eec2162 | |||
| 3adfd566bc | |||
| e6742a4e30 | |||
| 7472c66823 | |||
| c7873ef0ba | |||
| b79a20201e | |||
|
|
3ebf78805c | ||
| dcdea4236f | |||
| 11358c5bec | |||
| 9c21357059 | |||
| 909617d9b7 | |||
| ab952aa98f | |||
| a7bd8d5a3e | |||
| bc59f08bbb | |||
| 4c4d25f3b5 | |||
| 6af20575e8 | |||
| b6731f7641 | |||
| d2f81d7d3e | |||
| 59f38b9abb | |||
| 82c9c336f8 | |||
| f173089b14 | |||
| 4801203378 | |||
| 68a68a51a9 | |||
| e5b19d4ad9 | |||
| 7f8977f399 | |||
| 0214744184 | |||
| 9fe9246c55 | |||
| 9570730478 | |||
| 63b05c2307 | |||
| 328c1b0b88 | |||
| 3aa9303b3e | |||
| c2c29433b7 | |||
| 83638d918f | |||
| 64d5000b62 | |||
| 6e7c3226ab | |||
| 8e7731f554 | |||
| 7dc15760d5 | |||
| d48c6ddeb8 | |||
|
|
dce228123a | ||
|
|
3b220c3fd5 | ||
|
|
028af43510 | ||
|
|
a4a9e9914b | ||
|
|
ecdb4837d4 | ||
|
|
e29bbf4008 | ||
|
|
41a8fb41b1 | ||
|
|
ab6d99815e | ||
|
|
744d86fea4 | ||
|
|
fc26dcc9aa | ||
|
|
10c2592510 | ||
|
|
d9405eb536 | ||
|
|
4c9f468e08 | ||
|
|
c996ce660d | ||
|
|
ef1ad63b3f | ||
|
|
26c06a0908 | ||
|
|
b4cc3f9922 | ||
|
|
16b848adc9 | ||
|
|
4e94cf2091 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -74,3 +74,4 @@ crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
|
||||
|
||||
smartcsv.log
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
The MIT License (MIT)
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 Andreas Billmann <andreas.billmann@javafx.ninja>
|
||||
Copyright (c) 2015-2019 Andreas Billmann <andreas.billmann@javafx.ninja>
|
||||
|
||||
|
||||
|
||||
16
README.md
16
README.md
@@ -1,19 +1,29 @@
|
||||
# SmartCSV.fx
|
||||
## Description
|
||||
A simple JavaFX application to load, save and edit a CSV file and provide a JSON configuration for columns to check the values in the columns.
|
||||
A simple JavaFX application to load, save and edit a CSV file and provide a [JSON Table Schema](http://specs.frictionlessdata.io/json-table-schema/) for columns to check the values in the columns.
|
||||
|
||||
## Motivation
|
||||
At work I have the need to fix wrong CSV files from customers. It is hard to find the errors and fix them in a texteditor,
|
||||
even in a "normal" CSV editor. So I decided to write this simple JavaFX application.
|
||||
|
||||
## Video
|
||||
[](https://youtu.be/SH0UAtPG6Eg)
|
||||
[](https://youtu.be/eUh_WLx1OwI)
|
||||
|
||||
## Links
|
||||
[GitHub Page](http://frosch95.github.io/SmartCSV.fx/)
|
||||
|
||||
[Wiki & Documentation](https://github.com/frosch95/SmartCSV.fx/wiki)
|
||||
|
||||
binary distribution of the [latest release (0.9.1)](https://github.com/frosch95/SmartCSV.fx/releases/download/0.9.1/SmartCSV.fx-0.9.1-SNAPSHOT.zip)
|
||||
|
||||
## Talks
|
||||
[Introduction](http://javafx.ninja/talks/introduction/)
|
||||
|
||||
## License
|
||||
### The MIT License (MIT)
|
||||
|
||||
|
||||
Copyright (c) 2015 Andreas Billmann <andreas.billmann@javafx.ninja>
|
||||
Copyright (c) 2015-2016 Andreas Billmann <andreas.billmann@javafx.ninja>
|
||||
|
||||
|
||||
|
||||
|
||||
44
build.gradle
44
build.gradle
@@ -1,27 +1,39 @@
|
||||
group 'ninja.javafx'
|
||||
version '0.3-SNAPSHOT'
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'groovy'
|
||||
apply plugin:'application'
|
||||
apply plugin: 'idea'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
mainClassName = 'ninja.javafx.smartcsv.fx.SmartCSV'
|
||||
plugins {
|
||||
id 'idea'
|
||||
id 'java'
|
||||
id 'groovy'
|
||||
id 'application'
|
||||
id 'org.openjfx.javafxplugin' version '0.0.8'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
javafx {
|
||||
version = "13"
|
||||
modules = [ 'javafx.controls', 'javafx.fxml' ]
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3'
|
||||
testCompile group: 'org.mockito', name: 'mockito-all', version: '1.10.19'
|
||||
compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.5'
|
||||
compile group: 'org.springframework', name:'spring-context', version: '4.2.4.RELEASE'
|
||||
compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '3.0.0-beta-3'
|
||||
compile group: 'org.springframework', name:'spring-context', version: '5.2.0.RELEASE'
|
||||
compile group: 'net.sf.supercsv', name: 'super-csv', version: '2.4.0'
|
||||
compile group: 'com.typesafe', name: 'config', version: '1.3.0'
|
||||
compile group: 'commons-validator', name: 'commons-validator', version: '1.5.0'
|
||||
compile group: 'de.jensd', name: 'fontawesomefx', version: '8.8'
|
||||
compile group: 'commons-validator', name: 'commons-validator', version: '1.6'
|
||||
compile group: 'de.jensd', name: 'fontawesomefx-commons', version: '11.0'
|
||||
compile group: 'de.jensd', name: 'fontawesomefx-fontawesome', version: '4.7.0-11'
|
||||
compile group: 'de.jensd', name: 'fontawesomefx-materialdesignfont', version: '1.7.22-11'
|
||||
compile group: 'de.jensd', name: 'fontawesomefx-materialicons', version: '2.2.0-11'
|
||||
compile group: 'org.controlsfx', name: 'controlsfx', version: '11.0.0'
|
||||
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
|
||||
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.0'
|
||||
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.0'
|
||||
compile group: 'org.fxmisc.richtext', name: 'richtextfx', version: '0.10.2'
|
||||
}
|
||||
|
||||
group 'ninja.javafx'
|
||||
version '0.9.2-SNAPSHOT'
|
||||
mainClassName = 'ninja.javafx.smartcsv.Main'
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,5 @@
|
||||
#Thu Oct 01 19:02:27 CEST 2015
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip
|
||||
|
||||
74
gradlew
vendored
74
gradlew
vendored
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
@@ -6,12 +6,30 @@
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
@@ -30,6 +48,7 @@ die ( ) {
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
@@ -40,31 +59,11 @@ case "`uname`" in
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -90,7 +89,7 @@ location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
@@ -114,6 +113,7 @@ fi
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
@@ -154,11 +154,19 @@ if $cygwin ; then
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
14
gradlew.bat
vendored
14
gradlew.bat
vendored
@@ -8,14 +8,14 @@
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
@@ -46,10 +46,9 @@ echo location of your Java installation.
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
@@ -60,11 +59,6 @@ set _SKIP=2
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
rootProject.name = 'SmartCSV.ninja.javafx.smartcsv.fx'
|
||||
rootProject.name = 'SmartCSV.fx'
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -32,6 +32,7 @@ import java.io.IOException;
|
||||
/**
|
||||
* read some file
|
||||
*/
|
||||
public interface FileReader {
|
||||
public interface FileReader<E> {
|
||||
E getContent();
|
||||
void read(File filename) throws IOException;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -32,6 +32,7 @@ import java.io.IOException;
|
||||
/**
|
||||
* write some file
|
||||
*/
|
||||
public interface FileWriter {
|
||||
public interface FileWriter<E> {
|
||||
void setContent(E content);
|
||||
void write(File filename) throws IOException;
|
||||
}
|
||||
|
||||
10
src/main/java/ninja/javafx/smartcsv/Main.java
Normal file
10
src/main/java/ninja/javafx/smartcsv/Main.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package ninja.javafx.smartcsv;
|
||||
|
||||
import ninja.javafx.smartcsv.fx.SmartCSV;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
// workaround for module problem
|
||||
SmartCSV.main(args);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -29,7 +29,6 @@ package ninja.javafx.smartcsv.csv;
|
||||
import ninja.javafx.smartcsv.FileReader;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.supercsv.io.CsvMapReader;
|
||||
import org.supercsv.io.ICsvMapReader;
|
||||
|
||||
@@ -40,8 +39,7 @@ import java.util.Map;
|
||||
/**
|
||||
* reads the csv file and stores the values in csv model
|
||||
*/
|
||||
@Service
|
||||
public class CSVFileReader extends CSVConfigurable implements FileReader {
|
||||
public class CSVFileReader extends CSVConfigurable implements FileReader<CSVModel> {
|
||||
|
||||
private CSVModel model;
|
||||
|
||||
@@ -61,7 +59,7 @@ public class CSVFileReader extends CSVConfigurable implements FileReader {
|
||||
while ((customerMap = mapReader.read(header)) != null) {
|
||||
CSVRow row = model.addRow();
|
||||
for (String column : header) {
|
||||
row.addValue(column, customerMap.get(column));
|
||||
model.addValue(row, column, customerMap.get(column));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +70,7 @@ public class CSVFileReader extends CSVConfigurable implements FileReader {
|
||||
}
|
||||
}
|
||||
|
||||
public CSVModel getData() {
|
||||
public CSVModel getContent() {
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -28,7 +28,6 @@ package ninja.javafx.smartcsv.csv;
|
||||
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.supercsv.io.CsvMapWriter;
|
||||
import org.supercsv.io.ICsvMapWriter;
|
||||
|
||||
@@ -42,12 +41,11 @@ import static java.util.stream.Collectors.toMap;
|
||||
/**
|
||||
* filewriter for the csv
|
||||
*/
|
||||
@Service
|
||||
public class CSVFileWriter extends CSVConfigurable implements ninja.javafx.smartcsv.FileWriter {
|
||||
public class CSVFileWriter extends CSVConfigurable implements ninja.javafx.smartcsv.FileWriter<CSVModel> {
|
||||
|
||||
private CSVModel model;
|
||||
|
||||
public void setModel(CSVModel model) {
|
||||
public void setContent(CSVModel model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
|
||||
71
src/main/java/ninja/javafx/smartcsv/export/ErrorExport.java
Normal file
71
src/main/java/ninja/javafx/smartcsv/export/ErrorExport.java
Normal 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");
|
||||
model.getValidationError().forEach(error ->
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
78
src/main/java/ninja/javafx/smartcsv/files/FileStorage.java
Normal file
78
src/main/java/ninja/javafx/smartcsv/files/FileStorage.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package ninja.javafx.smartcsv.files;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import ninja.javafx.smartcsv.FileReader;
|
||||
import ninja.javafx.smartcsv.FileWriter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class stores files and their state
|
||||
* @author abi
|
||||
*/
|
||||
public class FileStorage<E> {
|
||||
|
||||
private FileReader<E> reader;
|
||||
private FileWriter<E> writer;
|
||||
|
||||
public FileStorage(FileReader<E> reader, FileWriter<E> writer) {
|
||||
this.reader = reader;
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
private BooleanProperty fileChanged = new SimpleBooleanProperty(true);
|
||||
private ObjectProperty<File> file = new SimpleObjectProperty<>();
|
||||
private ObjectProperty<E> content = new SimpleObjectProperty<>();
|
||||
|
||||
public boolean isFileChanged() {
|
||||
return fileChanged.get();
|
||||
}
|
||||
|
||||
public BooleanProperty fileChangedProperty() {
|
||||
return fileChanged;
|
||||
}
|
||||
|
||||
public void setFileChanged(boolean fileChanged) {
|
||||
this.fileChanged.set(fileChanged);
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return file.get();
|
||||
}
|
||||
|
||||
public ObjectProperty<File> fileProperty() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public void setFile(File file) {
|
||||
this.file.set(file);
|
||||
}
|
||||
|
||||
public E getContent() {
|
||||
return content.get();
|
||||
}
|
||||
|
||||
public ObjectProperty<E> contentProperty() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(E content) {
|
||||
this.content.set(content);
|
||||
}
|
||||
|
||||
public void load() throws IOException {
|
||||
reader.read(file.get());
|
||||
setContent(reader.getContent());
|
||||
setFileChanged(false);
|
||||
}
|
||||
|
||||
public void save() throws IOException {
|
||||
writer.setContent(content.get());
|
||||
writer.write(file.get());
|
||||
setFileChanged(false);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -28,11 +28,9 @@ package ninja.javafx.smartcsv.fx;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import ninja.javafx.smartcsv.fx.about.AboutController;
|
||||
import org.springframework.context.annotation.*;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -26,8 +26,10 @@
|
||||
|
||||
package ninja.javafx.smartcsv.fx;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.WeakListChangeListener;
|
||||
import javafx.concurrent.WorkerStateEvent;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
@@ -36,12 +38,13 @@ import javafx.scene.control.*;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.stage.FileChooser;
|
||||
import ninja.javafx.smartcsv.FileReader;
|
||||
import ninja.javafx.smartcsv.FileWriter;
|
||||
import ninja.javafx.smartcsv.csv.CSVFileReader;
|
||||
import ninja.javafx.smartcsv.csv.CSVFileWriter;
|
||||
import ninja.javafx.smartcsv.export.ErrorExport;
|
||||
import ninja.javafx.smartcsv.files.FileStorage;
|
||||
import ninja.javafx.smartcsv.fx.about.AboutController;
|
||||
import ninja.javafx.smartcsv.fx.list.ValidationErrorListCell;
|
||||
import ninja.javafx.smartcsv.fx.list.ErrorSideBar;
|
||||
import ninja.javafx.smartcsv.fx.list.GotoLineDialog;
|
||||
import ninja.javafx.smartcsv.fx.preferences.PreferencesController;
|
||||
import ninja.javafx.smartcsv.fx.table.ObservableMapValueFactory;
|
||||
import ninja.javafx.smartcsv.fx.table.ValidationCellFactory;
|
||||
@@ -50,10 +53,13 @@ import ninja.javafx.smartcsv.fx.table.model.CSVRow;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
|
||||
import ninja.javafx.smartcsv.fx.util.LoadFileService;
|
||||
import ninja.javafx.smartcsv.fx.util.SaveFileService;
|
||||
import ninja.javafx.smartcsv.fx.validation.ValidationEditorController;
|
||||
import ninja.javafx.smartcsv.preferences.PreferencesFileReader;
|
||||
import ninja.javafx.smartcsv.preferences.PreferencesFileWriter;
|
||||
import ninja.javafx.smartcsv.validation.configuration.ValidationConfiguration;
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
import ninja.javafx.smartcsv.validation.ValidationFileReader;
|
||||
import ninja.javafx.smartcsv.validation.ValidationFileWriter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -66,8 +72,10 @@ import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
import static java.text.MessageFormat.format;
|
||||
import static javafx.application.Platform.exit;
|
||||
import static javafx.application.Platform.runLater;
|
||||
import static javafx.beans.binding.Bindings.*;
|
||||
import static javafx.scene.layout.AnchorPane.*;
|
||||
|
||||
/**
|
||||
@@ -85,37 +93,35 @@ public class SmartCSVController extends FXMLController {
|
||||
".SmartCSV.fx" +
|
||||
File.separator + "" +
|
||||
"preferences.json");
|
||||
public static final String CSV_FILTER_TEXT = "CSV files (*.csv)";
|
||||
public static final String CSV_FILTER_EXTENSION = "*.csv";
|
||||
public static final String JSON_FILTER_TEXT = "JSON files (*.json)";
|
||||
public static final String JSON_FILTER_EXTENSION = "*.json";
|
||||
public static final String EXPORT_LOG_FILTER_TEXT = "Error log files (*.log)";
|
||||
public static final String EXPORT_LOG_FILTER_EXTENSION = "*.log";
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// injections
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Autowired
|
||||
private PreferencesFileReader preferencesLoader;
|
||||
|
||||
@Autowired
|
||||
private PreferencesFileWriter preferencesWriter;
|
||||
|
||||
@Autowired
|
||||
private CSVFileReader csvLoader;
|
||||
|
||||
@Autowired
|
||||
private ValidationFileReader validationLoader;
|
||||
|
||||
@Autowired
|
||||
private CSVFileWriter csvFileWriter;
|
||||
|
||||
@Autowired
|
||||
private AboutController aboutController;
|
||||
|
||||
@Autowired
|
||||
private PreferencesController preferencesController;
|
||||
|
||||
@Autowired
|
||||
private ValidationEditorController validationEditorController;
|
||||
|
||||
@Autowired
|
||||
private LoadFileService loadFileService;
|
||||
|
||||
@Autowired
|
||||
private SaveFileService saveFileService;;
|
||||
private SaveFileService saveFileService;
|
||||
|
||||
@Autowired
|
||||
private ErrorExport errorExport;
|
||||
|
||||
@FXML
|
||||
private BorderPane applicationPane;
|
||||
@@ -129,9 +135,6 @@ public class SmartCSVController extends FXMLController {
|
||||
@FXML
|
||||
private Label stateName;
|
||||
|
||||
@FXML
|
||||
private ListView errorList;
|
||||
|
||||
@FXML
|
||||
private AnchorPane tableWrapper;
|
||||
|
||||
@@ -141,6 +144,59 @@ public class SmartCSVController extends FXMLController {
|
||||
@FXML
|
||||
private MenuItem saveAsMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem createConfigMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem loadConfigMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem saveConfigMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem saveAsConfigMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem deleteRowMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem addRowMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem gotoLineMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem exportMenuItem;
|
||||
|
||||
@FXML
|
||||
private Button saveButton;
|
||||
|
||||
@FXML
|
||||
private Button saveAsButton;
|
||||
|
||||
@FXML
|
||||
private Button createConfigButton;
|
||||
|
||||
@FXML
|
||||
private Button loadConfigButton;
|
||||
|
||||
@FXML
|
||||
private Button saveConfigButton;
|
||||
|
||||
@FXML
|
||||
private Button saveAsConfigButton;
|
||||
|
||||
@FXML
|
||||
private Button deleteRowButton;
|
||||
|
||||
@FXML
|
||||
private Button addRowButton;
|
||||
|
||||
@FXML
|
||||
private Button exportButton;
|
||||
|
||||
@FXML
|
||||
private Label currentLineNumber;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// members
|
||||
@@ -148,13 +204,18 @@ public class SmartCSVController extends FXMLController {
|
||||
|
||||
private ValidationCellFactory cellFactory;
|
||||
|
||||
private CSVModel model;
|
||||
private TableView<CSVRow> tableView;
|
||||
private BooleanProperty fileChanged = new SimpleBooleanProperty(true);
|
||||
private ErrorSideBar errorSideBar;
|
||||
private ResourceBundle resourceBundle;
|
||||
private File currentCsvFile;
|
||||
private File currentConfigFile;
|
||||
private CSVFileReader csvFileReader = new CSVFileReader();
|
||||
private CSVFileWriter csvFileWriter = new CSVFileWriter();
|
||||
|
||||
private FileStorage<CSVModel> currentCsvFile = new FileStorage<>(csvFileReader, csvFileWriter);
|
||||
private FileStorage<ValidationConfiguration> currentConfigFile = new FileStorage<>(new ValidationFileReader(), new ValidationFileWriter());
|
||||
private FileStorage<CsvPreference> csvPreferenceFile = new FileStorage<>(new PreferencesFileReader(), new PreferencesFileWriter());
|
||||
|
||||
private ListChangeListener<ValidationError> errorListListener = c -> tableView.refresh();
|
||||
private WeakListChangeListener<ValidationError> weakErrorListListener = new WeakListChangeListener<>(errorListListener);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// init
|
||||
@@ -163,16 +224,35 @@ public class SmartCSVController extends FXMLController {
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resourceBundle) {
|
||||
this.resourceBundle = resourceBundle;
|
||||
saveFileService.setWriter(csvFileWriter);
|
||||
cellFactory = new ValidationCellFactory(resourceBundle);
|
||||
errorList.setCellFactory(param -> new ValidationErrorListCell(resourceBundle));
|
||||
errorList.getSelectionModel().selectedItemProperty().addListener(observable -> scrollToError());
|
||||
fileChanged.addListener(observable -> setStateName());
|
||||
setStateName();
|
||||
loadCsvPreferences();
|
||||
|
||||
setupTableCellFactory();
|
||||
setupErrorSideBar(resourceBundle);
|
||||
|
||||
bindMenuItemsToContentExistence(currentCsvFile, saveMenuItem, saveAsMenuItem, addRowMenuItem, gotoLineMenuItem, createConfigMenuItem, loadConfigMenuItem);
|
||||
bindButtonsToContentExistence(currentCsvFile, saveButton, saveAsButton, addRowButton, createConfigButton, loadConfigButton);
|
||||
|
||||
bindMenuItemsToContentExistence(currentConfigFile, saveConfigMenuItem, saveAsConfigMenuItem);
|
||||
bindButtonsToContentExistence(currentConfigFile, saveAsConfigButton, saveConfigButton);
|
||||
|
||||
bindCsvFileName();
|
||||
bindConfigFileName();
|
||||
|
||||
csvPreferenceFile.setFile(PREFERENCES_FILE);
|
||||
|
||||
loadCsvPreferencesFromFile();
|
||||
}
|
||||
|
||||
private void setupErrorSideBar(ResourceBundle resourceBundle) {
|
||||
errorSideBar = new ErrorSideBar(resourceBundle);
|
||||
errorSideBar.selectedValidationErrorProperty().addListener((observable, oldValue, newValue) -> {
|
||||
scrollToError(newValue);
|
||||
});
|
||||
applicationPane.setRight(errorSideBar);
|
||||
}
|
||||
|
||||
private void setupTableCellFactory() {
|
||||
cellFactory = new ValidationCellFactory(resourceBundle);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -192,39 +272,44 @@ public class SmartCSVController extends FXMLController {
|
||||
|
||||
@FXML
|
||||
public void openCsv(ActionEvent actionEvent) {
|
||||
currentCsvFile = loadFile(csvLoader,
|
||||
"CSV files (*.csv)",
|
||||
"*.csv",
|
||||
"Open CSV",
|
||||
currentCsvFile);
|
||||
enableSaveMenuItems();
|
||||
setCsvFileName();
|
||||
loadFile(CSV_FILTER_TEXT, CSV_FILTER_EXTENSION, "Open CSV", currentCsvFile);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void openConfig(ActionEvent actionEvent) {
|
||||
currentConfigFile = loadFile(validationLoader,
|
||||
"JSON files (*.json)",
|
||||
"*.json",
|
||||
"Open Validation Configuration",
|
||||
currentConfigFile);
|
||||
setConfigFileName();
|
||||
loadFile(JSON_FILTER_TEXT, JSON_FILTER_EXTENSION, "Open Validation Configuration", currentConfigFile);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void createConfig(ActionEvent actionEvent) {
|
||||
currentConfigFile.setContent(currentCsvFile.getContent().createValidationConfiguration());
|
||||
currentConfigFile.setFile(null);
|
||||
currentConfigFile.setFileChanged(true);
|
||||
resetContent();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void saveCsv(ActionEvent actionEvent) {
|
||||
csvFileWriter.setModel(model);
|
||||
useSaveFileService(csvFileWriter, currentCsvFile);
|
||||
useSaveFileService(currentCsvFile);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void saveAsCsv(ActionEvent actionEvent) {
|
||||
csvFileWriter.setModel(model);
|
||||
currentCsvFile = saveFile(csvFileWriter,
|
||||
"CSV files (*.csv)",
|
||||
"*.csv",
|
||||
currentCsvFile);
|
||||
setCsvFileName();
|
||||
saveFile(CSV_FILTER_TEXT, CSV_FILTER_EXTENSION, currentCsvFile);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void saveConfig(ActionEvent actionEvent) {
|
||||
if (currentConfigFile.getFile() == null) {
|
||||
saveAsConfig(actionEvent);
|
||||
} else {
|
||||
useSaveFileService(currentConfigFile);
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void saveAsConfig(ActionEvent actionEvent) {
|
||||
saveFile(JSON_FILTER_TEXT, JSON_FILTER_EXTENSION, currentConfigFile);
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -261,13 +346,69 @@ public class SmartCSVController extends FXMLController {
|
||||
setCsvPreference(csvPreference);
|
||||
saveCsvPreferences(csvPreference);
|
||||
} else {
|
||||
preferencesController.setCsvPreference(preferencesLoader.getCSVpreference());
|
||||
preferencesController.setCsvPreference(csvPreferenceFile.getContent());
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void deleteRow(ActionEvent actionEvent) {
|
||||
currentCsvFile.getContent().getRows().removeAll(tableView.getSelectionModel().getSelectedItems());
|
||||
currentCsvFile.setFileChanged(true);
|
||||
resetContent();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void addRow(ActionEvent actionEvent) {
|
||||
CSVRow row = currentCsvFile.getContent().addRow();
|
||||
for (String column : currentCsvFile.getContent().getHeader()) {
|
||||
currentCsvFile.getContent().addValue(row, column, "");
|
||||
}
|
||||
currentCsvFile.setFileChanged(true);
|
||||
resetContent();
|
||||
|
||||
selectNewRow();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void gotoLine(ActionEvent actionEvent) {
|
||||
int maxLineNumber = currentCsvFile.getContent().getRows().size();
|
||||
GotoLineDialog dialog = new GotoLineDialog(maxLineNumber);
|
||||
dialog.setTitle(resourceBundle.getString("dialog.goto.line.title"));
|
||||
dialog.setHeaderText(format(resourceBundle.getString("dialog.goto.line.header.text"), maxLineNumber));
|
||||
dialog.setContentText(resourceBundle.getString("dialog.goto.line.label"));
|
||||
Optional<Integer> result = dialog.showAndWait();
|
||||
if (result.isPresent()){
|
||||
Integer lineNumber = result.get();
|
||||
if (lineNumber != null) {
|
||||
tableView.scrollTo(max(0, lineNumber - 2));
|
||||
tableView.getSelectionModel().select(lineNumber - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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() {
|
||||
boolean canExit = true;
|
||||
if (model != null && fileChanged.get()) {
|
||||
if (currentCsvFile.getContent() != null && currentCsvFile.isFileChanged()) {
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
alert.setTitle(resourceBundle.getString("dialog.exit.title"));
|
||||
alert.setHeaderText(resourceBundle.getString("dialog.exit.header.text"));
|
||||
@@ -282,74 +423,115 @@ public class SmartCSVController extends FXMLController {
|
||||
return canExit;
|
||||
}
|
||||
|
||||
public void showValidationEditor(String column) {
|
||||
validationEditorController.setSelectedColumn(column);
|
||||
validationEditorController.updateForm();
|
||||
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
alert.setGraphic(null);
|
||||
alert.setTitle(resourceBundle.getString("dialog.validation.rules.title"));
|
||||
alert.setHeaderText(format(resourceBundle.getString("dialog.validation.rules.header"), column));
|
||||
alert.getDialogPane().setContent(validationEditorController.getView());
|
||||
Optional<ButtonType> result = alert.showAndWait();
|
||||
|
||||
if (result.get() == ButtonType.OK){
|
||||
runLater(() -> {
|
||||
validationEditorController.updateConfiguration();
|
||||
currentCsvFile.setFileChanged(true);
|
||||
currentCsvFile.getContent().revalidate(column);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// private methods
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void enableSaveMenuItems() {
|
||||
if (currentCsvFile != null) {
|
||||
saveMenuItem.setDisable(false);
|
||||
saveAsMenuItem.setDisable(false);
|
||||
private void selectNewRow() {
|
||||
int lastRow = tableView.getItems().size()-1;
|
||||
tableView.scrollTo(lastRow);
|
||||
tableView.requestFocus();
|
||||
tableView.getSelectionModel().select(lastRow);
|
||||
}
|
||||
|
||||
private void bindMenuItemsToContentExistence(FileStorage file, MenuItem... items) {
|
||||
for (MenuItem item: items) {
|
||||
item.disableProperty().bind(isNull(file.contentProperty()));
|
||||
}
|
||||
}
|
||||
|
||||
private void setCsvFileName() {
|
||||
if (currentCsvFile != null) {
|
||||
csvName.setText(currentCsvFile.getName());
|
||||
private void bindButtonsToContentExistence(FileStorage file, Button... items) {
|
||||
for (Button item: items) {
|
||||
item.disableProperty().bind(isNull(file.contentProperty()));
|
||||
}
|
||||
}
|
||||
|
||||
private void bindMenuItemsToTableSelection(MenuItem... items) {
|
||||
for (MenuItem item: items) {
|
||||
item.disableProperty().bind(lessThan(tableView.getSelectionModel().selectedIndexProperty(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
private void bindButtonsToTableSelection(Button... items) {
|
||||
for (Button item: items) {
|
||||
item.disableProperty().bind(lessThan(tableView.getSelectionModel().selectedIndexProperty(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
private void bindCsvFileName() {
|
||||
csvName.textProperty().bind(selectString(currentCsvFile.fileProperty(), "name"));
|
||||
}
|
||||
|
||||
private void bindConfigFileName() {
|
||||
configurationName.textProperty().bind(selectString(currentConfigFile.fileProperty(), "name"));
|
||||
}
|
||||
|
||||
private void bindLineNumber() {
|
||||
currentLineNumber.textProperty().bind(tableView.getSelectionModel().selectedIndexProperty().add(1).asString());
|
||||
}
|
||||
|
||||
private void loadCsvPreferencesFromFile() {
|
||||
if (csvPreferenceFile.getFile().exists()) {
|
||||
useLoadFileService(csvPreferenceFile, event -> setCsvPreference(csvPreferenceFile.getContent()));
|
||||
} else {
|
||||
csvName.setText("");
|
||||
setCsvPreference(CsvPreference.EXCEL_NORTH_EUROPE_PREFERENCE);
|
||||
}
|
||||
}
|
||||
|
||||
private void setConfigFileName() {
|
||||
if (currentConfigFile != null) {
|
||||
configurationName.setText(currentConfigFile.getName());
|
||||
} else {
|
||||
configurationName.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
private void loadCsvPreferences() {
|
||||
if (PREFERENCES_FILE.exists()) {
|
||||
useLoadFileService(preferencesLoader, PREFERENCES_FILE);
|
||||
}
|
||||
setCsvPreference(preferencesLoader.getCSVpreference());
|
||||
}
|
||||
|
||||
private void saveCsvPreferences(CsvPreference csvPreference) {
|
||||
try {
|
||||
createPreferenceFile();
|
||||
preferencesWriter.setCsvPreference(csvPreference);
|
||||
useSaveFileService(preferencesWriter, PREFERENCES_FILE);
|
||||
csvPreferenceFile.setContent(csvPreference);
|
||||
useSaveFileService(csvPreferenceFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void createPreferenceFile() throws IOException {
|
||||
if (!PREFERENCES_FILE.exists()) {
|
||||
if (!csvPreferenceFile.getFile().exists()) {
|
||||
createPreferencesFileFolder();
|
||||
PREFERENCES_FILE.createNewFile();
|
||||
csvPreferenceFile.getFile().createNewFile();
|
||||
}
|
||||
}
|
||||
|
||||
private void createPreferencesFileFolder() {
|
||||
if (!PREFERENCES_FILE.getParentFile().exists()) {
|
||||
PREFERENCES_FILE.getParentFile().mkdir();
|
||||
if (!csvPreferenceFile.getFile().getParentFile().exists()) {
|
||||
csvPreferenceFile.getFile().getParentFile().mkdir();
|
||||
}
|
||||
}
|
||||
|
||||
private void setCsvPreference(CsvPreference csvPreference) {
|
||||
csvLoader.setCsvPreference(csvPreference);
|
||||
csvFileWriter.setCsvPreference(csvPreference);
|
||||
preferencesController.setCsvPreference(csvPreference);
|
||||
csvFileReader.setCsvPreference(csvPreference);
|
||||
csvFileWriter.setCsvPreference(csvPreference);
|
||||
|
||||
}
|
||||
|
||||
private File loadFile(FileReader fileReader,
|
||||
String filterText,
|
||||
private void loadFile(String filterText,
|
||||
String filter,
|
||||
String title,
|
||||
File initChildFile) {
|
||||
FileStorage storageFile) {
|
||||
final FileChooser fileChooser = new FileChooser();
|
||||
|
||||
//Set extension filter
|
||||
@@ -357,77 +539,76 @@ public class SmartCSVController extends FXMLController {
|
||||
fileChooser.getExtensionFilters().add(extFilter);
|
||||
fileChooser.setTitle(title);
|
||||
|
||||
if (initChildFile != null) {
|
||||
fileChooser.setInitialDirectory(initChildFile.getParentFile());
|
||||
if (storageFile.getFile() != null) {
|
||||
fileChooser.setInitialDirectory(storageFile.getFile().getParentFile());
|
||||
}
|
||||
|
||||
//Show open file dialog
|
||||
File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow());
|
||||
if (file != null) {
|
||||
useLoadFileService(fileReader, file);
|
||||
return file;
|
||||
} else {
|
||||
return initChildFile;
|
||||
storageFile.setFile(file);
|
||||
useLoadFileService(storageFile, t -> resetContent());
|
||||
}
|
||||
}
|
||||
|
||||
private File saveFile(FileWriter writer, String filterText, String filter, File initFile) {
|
||||
File file = initFile;
|
||||
if (model != null) {
|
||||
private File saveFile(String filterText, String filter, FileStorage fileStorage) {
|
||||
File file = fileStorage.getFile();
|
||||
if (fileStorage.getContent() != null) {
|
||||
final FileChooser fileChooser = new FileChooser();
|
||||
|
||||
//Set extension filter
|
||||
final FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(filterText, filter);
|
||||
fileChooser.getExtensionFilters().add(extFilter);
|
||||
|
||||
if (initFile != null) {
|
||||
fileChooser.setInitialDirectory(initFile.getParentFile());
|
||||
fileChooser.setInitialFileName(initFile.getName());
|
||||
if (fileStorage.getFile() != null) {
|
||||
fileChooser.setInitialDirectory(fileStorage.getFile().getParentFile());
|
||||
fileChooser.setInitialFileName(fileStorage.getFile().getName());
|
||||
}
|
||||
fileChooser.setTitle("Save File");
|
||||
|
||||
//Show open file dialog
|
||||
file = fileChooser.showSaveDialog(applicationPane.getScene().getWindow());
|
||||
if (file != null) {
|
||||
useSaveFileService(writer, file);
|
||||
fileStorage.setFile(file);
|
||||
useSaveFileService(fileStorage);
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private void useLoadFileService(FileReader fileReader, File file) {
|
||||
loadFileService.setFile(file);
|
||||
loadFileService.setFileReader(fileReader);
|
||||
private void useLoadFileService(FileStorage fileStorage, EventHandler<WorkerStateEvent> onSucceededHandler) {
|
||||
loadFileService.setFileStorage(fileStorage);
|
||||
loadFileService.restart();
|
||||
loadFileService.setOnSucceeded(event -> runLater(() -> {
|
||||
resetContent();
|
||||
fileChanged.setValue(false);
|
||||
}));
|
||||
loadFileService.setOnSucceeded(onSucceededHandler);
|
||||
}
|
||||
|
||||
private void useSaveFileService(FileWriter writer, File file) {
|
||||
saveFileService.setFile(file);
|
||||
saveFileService.setWriter(writer);
|
||||
private void useSaveFileService(FileStorage fileStorage) {
|
||||
saveFileService.setFileStorage(fileStorage);
|
||||
saveFileService.restart();
|
||||
saveFileService.setOnSucceeded(event -> runLater(() -> {
|
||||
resetContent();
|
||||
fileChanged.setValue(false);
|
||||
}));
|
||||
saveFileService.setOnSucceeded(t -> resetContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new table view and add the new content
|
||||
*/
|
||||
private void resetContent() {
|
||||
model = csvLoader.getData();
|
||||
if (model != null) {
|
||||
model.setValidator(validationLoader.getValidator());
|
||||
tableView = new TableView<>();
|
||||
resetExportButtons();
|
||||
|
||||
for (String column : model.getHeader()) {
|
||||
if (currentCsvFile.getContent() != null) {
|
||||
currentCsvFile.getContent().getValidationError().addListener(weakErrorListListener);
|
||||
currentCsvFile.getContent().setValidationConfiguration(currentConfigFile.getContent());
|
||||
validationEditorController.setValidationConfiguration(currentConfigFile.getContent());
|
||||
tableView = new TableView<>();
|
||||
bindLineNumber();
|
||||
|
||||
bindMenuItemsToTableSelection(deleteRowMenuItem);
|
||||
bindButtonsToTableSelection(deleteRowButton);
|
||||
|
||||
for (String column : currentCsvFile.getContent().getHeader()) {
|
||||
addColumn(column, tableView);
|
||||
}
|
||||
tableView.getItems().setAll(model.getRows());
|
||||
|
||||
tableView.getItems().setAll(currentCsvFile.getContent().getRows());
|
||||
tableView.setEditable(true);
|
||||
|
||||
setBottomAnchor(tableView, 0.0);
|
||||
@@ -435,29 +616,45 @@ public class SmartCSVController extends FXMLController {
|
||||
setLeftAnchor(tableView, 0.0);
|
||||
setRightAnchor(tableView, 0.0);
|
||||
tableWrapper.getChildren().setAll(tableView);
|
||||
|
||||
errorList.setItems(model.getValidationError());
|
||||
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
|
||||
* @param header name of the column header
|
||||
* @param tableView the tableview
|
||||
*/
|
||||
private void addColumn(String header, TableView tableView) {
|
||||
private void addColumn(final String header, TableView tableView) {
|
||||
TableColumn column = new TableColumn(header);
|
||||
column.setCellValueFactory(new ObservableMapValueFactory(header));
|
||||
column.setCellFactory(cellFactory);
|
||||
column.setEditable(true);
|
||||
column.setSortable(false);
|
||||
|
||||
ContextMenu contextMenu = contextMenuForColumn(header);
|
||||
column.setContextMenu(contextMenu);
|
||||
|
||||
column.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<CSVRow, CSVValue>>() {
|
||||
@Override
|
||||
public void handle(TableColumn.CellEditEvent<CSVRow, CSVValue> event) {
|
||||
event.getTableView().getItems().get(event.getTablePosition().getRow()).
|
||||
getColumns().get(header).setValue(event.getNewValue());
|
||||
runLater(() -> {
|
||||
fileChanged.setValue(true);
|
||||
model.revalidate();
|
||||
currentCsvFile.setFileChanged(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -465,8 +662,16 @@ public class SmartCSVController extends FXMLController {
|
||||
tableView.getColumns().add(column);
|
||||
}
|
||||
|
||||
private void scrollToError() {
|
||||
ValidationError entry = (ValidationError)errorList.getSelectionModel().getSelectedItem();
|
||||
private ContextMenu contextMenuForColumn(String header) {
|
||||
ContextMenu contextMenu = new ContextMenu();
|
||||
MenuItem editColumnRulesMenuItem = new MenuItem(resourceBundle.getString("context.menu.edit.column.rules"));
|
||||
bindMenuItemsToContentExistence(currentConfigFile, editColumnRulesMenuItem);
|
||||
editColumnRulesMenuItem.setOnAction(e -> showValidationEditor(header));
|
||||
contextMenu.getItems().addAll(editColumnRulesMenuItem);
|
||||
return contextMenu;
|
||||
}
|
||||
|
||||
private void scrollToError(ValidationError entry) {
|
||||
if (entry != null) {
|
||||
if (entry.getLineNumber() != null) {
|
||||
tableView.scrollTo(max(0, entry.getLineNumber() - 1));
|
||||
@@ -476,16 +681,4 @@ public class SmartCSVController extends FXMLController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setStateName() {
|
||||
if (model != null) {
|
||||
if (fileChanged.get()) {
|
||||
stateName.setText(resourceBundle.getString("state.changed"));
|
||||
} else {
|
||||
stateName.setText(resourceBundle.getString("state.unchanged"));
|
||||
}
|
||||
} else {
|
||||
stateName.setText("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
|
||||
173
src/main/java/ninja/javafx/smartcsv/fx/list/ErrorSideBar.java
Normal file
173
src/main/java/ninja/javafx/smartcsv/fx/list/ErrorSideBar.java
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 javafx.ninja <info@javafx.ninja>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.fx.list;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.WeakListChangeListener;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Text;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.controlsfx.control.PopOver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static javafx.geometry.Pos.CENTER;
|
||||
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.I18nValidationUtil.getI18nValidatioMessageWithColumn;
|
||||
|
||||
/**
|
||||
* clickable side bar with error markers
|
||||
*/
|
||||
public class ErrorSideBar extends Region {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(ErrorSideBar.class);
|
||||
|
||||
private static final double WIDTH = 20.0;
|
||||
private static final int BORDER = 8;
|
||||
private static final double STATUS_BLOCK_HEIGHT = WIDTH - BORDER;
|
||||
private static final double STATUS_BLOCK_WIDTH = WIDTH - BORDER;
|
||||
private static final double STATUS_BLOCK_OFFSET = WIDTH + BORDER / 2;
|
||||
|
||||
private ListChangeListener<ValidationError> errorListListener = c -> setErrorMarker();
|
||||
private WeakListChangeListener<ValidationError> weakErrorListListener = new WeakListChangeListener<>(errorListListener);
|
||||
private ObjectProperty<CSVModel> model = new SimpleObjectProperty<>();
|
||||
private ObjectProperty<ValidationError> selectedValidationError = new SimpleObjectProperty<>();
|
||||
private PopOver popOver = new PopOver();
|
||||
private ResourceBundle resourceBundle;
|
||||
private Region statusBlock;
|
||||
|
||||
public ErrorSideBar(ResourceBundle resourceBundle) {
|
||||
this.resourceBundle = resourceBundle;
|
||||
initPopOver();
|
||||
setFixWidth();
|
||||
addModelListener();
|
||||
|
||||
statusBlock = new Region();
|
||||
statusBlock.setPrefSize(STATUS_BLOCK_WIDTH, STATUS_BLOCK_HEIGHT);
|
||||
statusBlock.setLayoutY(BORDER / 2);
|
||||
statusBlock.setLayoutX(BORDER / 2);
|
||||
}
|
||||
|
||||
private void initPopOver() {
|
||||
popOver.setAutoHide(true);
|
||||
popOver.setArrowLocation(PopOver.ArrowLocation.RIGHT_CENTER);
|
||||
}
|
||||
|
||||
public void setModel(CSVModel model) {
|
||||
this.model.set(model);
|
||||
}
|
||||
|
||||
public CSVModel getModel() {
|
||||
return model.get();
|
||||
}
|
||||
|
||||
public ObjectProperty<CSVModel> modelProperty() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public ValidationError getSelectedValidationError() {
|
||||
return selectedValidationError.get();
|
||||
}
|
||||
|
||||
public ObjectProperty<ValidationError> selectedValidationErrorProperty() {
|
||||
return selectedValidationError;
|
||||
}
|
||||
|
||||
public void setSelectedValidationError(ValidationError selectedValidationError) {
|
||||
this.selectedValidationError.set(selectedValidationError);
|
||||
}
|
||||
|
||||
private void addModelListener() {
|
||||
model.addListener((observable, oldValue, newValue) -> {
|
||||
newValue.getValidationError().addListener(weakErrorListListener);
|
||||
setErrorMarker();
|
||||
});
|
||||
}
|
||||
|
||||
private void setFixWidth() {
|
||||
setMinWidth(WIDTH);
|
||||
setPrefWidth(WIDTH);
|
||||
setMaxWidth(WIDTH);
|
||||
}
|
||||
|
||||
private void setErrorMarker() {
|
||||
List<Region> errorMarkerList = new ArrayList<>();
|
||||
errorMarkerList.add(statusBlock);
|
||||
statusBlock.setStyle("-fx-background-color: " + OK_COLOR);
|
||||
if (model.get() != null) {
|
||||
List<ValidationError> errorList = model.get().getValidationError();
|
||||
if (errorList != null && !errorList.isEmpty()) {
|
||||
|
||||
statusBlock.setStyle("-fx-background-color: " + ERROR_COLOR);
|
||||
|
||||
int rows = model.get().getRows().size();
|
||||
double space = (double)heightWithoutStatusBlock() / rows;
|
||||
errorList.forEach(error -> errorMarkerList.add(generateErrorMarker(space, error)));
|
||||
}
|
||||
}
|
||||
getChildren().setAll(errorMarkerList);
|
||||
}
|
||||
|
||||
private int heightWithoutStatusBlock() {
|
||||
return (int)(getHeight() - STATUS_BLOCK_OFFSET);
|
||||
}
|
||||
|
||||
private Region generateErrorMarker(double space, ValidationError error) {
|
||||
logger.info("generate error marker for {} errors in line {}", error.getMessages().size(), error.getLineNumber());
|
||||
logger.info("layout y is set to {}", (space * error.getLineNumber() + STATUS_BLOCK_OFFSET));
|
||||
Region errorMarker = new Region();
|
||||
errorMarker.setLayoutY(space * error.getLineNumber() + STATUS_BLOCK_OFFSET);
|
||||
errorMarker.setPrefSize(WIDTH, 2);
|
||||
errorMarker.setStyle("-fx-background-color: " + ERROR_COLOR);
|
||||
errorMarker.setOnMouseClicked(event -> selectedValidationError.setValue(error));
|
||||
errorMarker.setOnMouseEntered(event -> {
|
||||
popOver.setContentNode(popupContent(getI18nValidatioMessageWithColumn(resourceBundle, error)));
|
||||
popOver.show(errorMarker, -16);
|
||||
});
|
||||
return errorMarker;
|
||||
}
|
||||
|
||||
private Node popupContent(String text) {
|
||||
VBox vBox = new VBox();
|
||||
vBox.setPadding(new Insets(10,10,10,10));
|
||||
vBox.getChildren().add(new Text(text));
|
||||
vBox.setAlignment(CENTER);
|
||||
return vBox;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package ninja.javafx.smartcsv.fx.list;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
/**
|
||||
* Created by abi on 05.08.2016.
|
||||
*/
|
||||
public class GotoLineDialog extends Dialog<Integer> {
|
||||
|
||||
private final GridPane grid;
|
||||
private final Label label;
|
||||
private final TextField textField;
|
||||
|
||||
public GotoLineDialog(int maxLineNumber) {
|
||||
final DialogPane dialogPane = getDialogPane();
|
||||
|
||||
this.textField = new TextField("");
|
||||
this.textField.setMaxWidth(Double.MAX_VALUE);
|
||||
|
||||
UnaryOperator<TextFormatter.Change> filter = change -> {
|
||||
String text = change.getText();
|
||||
|
||||
if (text.matches("[0-9]*")) {
|
||||
try {
|
||||
int lineNumber = Integer.parseInt(textField.getText() + text);
|
||||
if (lineNumber <= maxLineNumber) {
|
||||
return change;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// this happens when focusing textfield or press special keys like DEL
|
||||
return change;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
TextFormatter<String> textFormatter = new TextFormatter<>(filter);
|
||||
textField.setTextFormatter(textFormatter);
|
||||
|
||||
GridPane.setHgrow(textField, Priority.ALWAYS);
|
||||
GridPane.setFillWidth(textField, true);
|
||||
|
||||
label = createContentLabel(dialogPane.getContentText());
|
||||
label.setPrefWidth(Region.USE_COMPUTED_SIZE);
|
||||
label.textProperty().bind(dialogPane.contentTextProperty());
|
||||
|
||||
this.grid = new GridPane();
|
||||
this.grid.setHgap(10);
|
||||
this.grid.setMaxWidth(Double.MAX_VALUE);
|
||||
this.grid.setAlignment(Pos.CENTER_LEFT);
|
||||
|
||||
dialogPane.contentTextProperty().addListener(o -> updateGrid());
|
||||
|
||||
dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
|
||||
|
||||
updateGrid();
|
||||
|
||||
setResultConverter((dialogButton) -> {
|
||||
ButtonBar.ButtonData data = dialogButton == null ? null : dialogButton.getButtonData();
|
||||
return data == ButtonBar.ButtonData.OK_DONE ? Integer.parseInt(textField.getText()) : null;
|
||||
});
|
||||
}
|
||||
|
||||
private Label createContentLabel(String text) {
|
||||
Label label = new Label(text);
|
||||
label.setMaxWidth(Double.MAX_VALUE);
|
||||
label.setMaxHeight(Double.MAX_VALUE);
|
||||
label.getStyleClass().add("content");
|
||||
label.setWrapText(true);
|
||||
label.setPrefWidth(360);
|
||||
return label;
|
||||
}
|
||||
|
||||
private void updateGrid() {
|
||||
grid.getChildren().clear();
|
||||
|
||||
grid.add(label, 0, 0);
|
||||
grid.add(textField, 1, 0);
|
||||
getDialogPane().setContent(grid);
|
||||
|
||||
Platform.runLater(() -> textField.requestFocus());
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -26,12 +26,8 @@
|
||||
|
||||
package ninja.javafx.smartcsv.fx.preferences;
|
||||
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ComboBox;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -37,6 +37,7 @@ import ninja.javafx.smartcsv.fx.table.model.CSVValue;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static javafx.application.Platform.runLater;
|
||||
import static ninja.javafx.smartcsv.fx.util.ColorConstants.ERROR_COLOR;
|
||||
import static ninja.javafx.smartcsv.fx.util.I18nValidationUtil.getI18nValidatioMessage;
|
||||
|
||||
/**
|
||||
@@ -77,7 +78,7 @@ public class EditableValidationCell extends TableCell<CSVRow, CSVValue> {
|
||||
setStyle("");
|
||||
setTooltip(null);
|
||||
} else if (item.getValidationError() != null) {
|
||||
setStyle("-fx-background-color: #ff8888");
|
||||
setStyle("-fx-background-color: derive("+ ERROR_COLOR +", 30%)");
|
||||
setTooltip(new Tooltip(getI18nValidatioMessage(resourceBundle, item.getValidationError())));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -28,31 +28,40 @@ package ninja.javafx.smartcsv.fx.table.model;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import ninja.javafx.smartcsv.validation.RevalidationService;
|
||||
import ninja.javafx.smartcsv.validation.configuration.ValidationConfiguration;
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
import ninja.javafx.smartcsv.validation.Validator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* The CSVModel is the client representation for the csv filepath.
|
||||
* 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 Validator validator;
|
||||
private ObservableList<CSVRow> rows = FXCollections.observableArrayList();
|
||||
private String[] header;
|
||||
private ObservableList<ValidationError> validationError = FXCollections.observableArrayList();
|
||||
private RevalidationService revalidationService = new RevalidationService();
|
||||
|
||||
/**
|
||||
* sets the validator for the data revalidates
|
||||
* @param validator the validator for this data
|
||||
* sets the validator configuration for the data revalidates
|
||||
*
|
||||
* @param validationConfiguration the validator configuration for this data
|
||||
*/
|
||||
public void setValidator(Validator validator) {
|
||||
this.validator = validator;
|
||||
public void setValidationConfiguration(ValidationConfiguration validationConfiguration) {
|
||||
this.validator = new Validator(validationConfiguration, this);
|
||||
revalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the data as a list of rows of the
|
||||
*
|
||||
* @return list of rows
|
||||
*/
|
||||
public ObservableList<CSVRow> getRows() {
|
||||
@@ -65,18 +74,30 @@ public class CSVModel {
|
||||
|
||||
/**
|
||||
* adds a new and empty row
|
||||
*
|
||||
* @return the new row
|
||||
*/
|
||||
public CSVRow addRow() {
|
||||
CSVRow row = new CSVRow();
|
||||
row.setValidator(validator);
|
||||
row.setRowNumber(rows.size());
|
||||
rows.add(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
|
||||
*
|
||||
* @param header the headers of the columns
|
||||
*/
|
||||
public void setHeader(String[] header) {
|
||||
@@ -86,6 +107,7 @@ public class CSVModel {
|
||||
|
||||
/**
|
||||
* returns the column headers
|
||||
*
|
||||
* @return the column headers
|
||||
*/
|
||||
public String[] getHeader() {
|
||||
@@ -93,41 +115,49 @@ public class CSVModel {
|
||||
}
|
||||
|
||||
|
||||
public void revalidate(String column) {
|
||||
if (!hasValidator()) return;
|
||||
validator.reinitializeColumn(column);
|
||||
revalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* walks through the data and validates each value
|
||||
*/
|
||||
public void revalidate() {
|
||||
validationError.clear();
|
||||
|
||||
if (header != null && validator != null) {
|
||||
addValidationError(validator.isHeaderValid(header));
|
||||
logger.info("revalidate: hasValidator -> {}", hasValidator());
|
||||
|
||||
if (!hasValidator()) return;
|
||||
revalidationService.setHeader(header);
|
||||
revalidationService.setRows(rows);
|
||||
revalidationService.setValidator(validator);
|
||||
revalidationService.setOnSucceeded(t -> validationError.setAll(revalidationService.getValue()));
|
||||
revalidationService.setOnFailed(t -> logger.error("revalidation service failed!"));
|
||||
revalidationService.restart();
|
||||
}
|
||||
|
||||
for (int lineNumber = 0; lineNumber < rows.size(); lineNumber++) {
|
||||
CSVRow row = rows.get(lineNumber);
|
||||
row.setValidator(validator);
|
||||
for (String column: row.getColumns().keySet()) {
|
||||
CSVValue value = row.getColumns().get(column).getValue();
|
||||
value.setValidator(validator);
|
||||
if (validator != null) {
|
||||
ValidationError validationError = validator.isValid(column, value.getValue(), lineNumber);
|
||||
if (validationError != null) {
|
||||
addValidationError(validationError);
|
||||
value.setValidationError(validationError);
|
||||
} else {
|
||||
value.setValidationError(null);
|
||||
}
|
||||
} else {
|
||||
value.setValidationError(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
private boolean hasValidator() {
|
||||
return validator != null && validator.hasConfig();
|
||||
}
|
||||
|
||||
private void addValidationError(ValidationError validationError) {
|
||||
if (validationError != null) {
|
||||
this.validationError.add(validationError);
|
||||
}
|
||||
public ValidationConfiguration createValidationConfiguration() {
|
||||
ValidationConfiguration newValidationConfiguration = new ValidationConfiguration();
|
||||
newValidationConfiguration.setHeaderNames(this.header);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -30,24 +30,14 @@ import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableMap;
|
||||
import ninja.javafx.smartcsv.validation.Validator;
|
||||
|
||||
/**
|
||||
* This class represents a single row in the csv file.
|
||||
*/
|
||||
public class CSVRow {
|
||||
private Validator validator;
|
||||
private ObservableMap<String, ObjectProperty<CSVValue>> columns = FXCollections.observableHashMap();
|
||||
private int rowNumber;
|
||||
|
||||
/**
|
||||
* single row
|
||||
* @param validator the reference to the validator
|
||||
*/
|
||||
public void setValidator(Validator validator) {
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the row number
|
||||
* @param rowNumber
|
||||
@@ -78,13 +68,11 @@ public class CSVRow {
|
||||
* @param column column name
|
||||
* @param value the value to store
|
||||
*/
|
||||
public void addValue(String column, String value) {
|
||||
CSVValue addValue(String column, String value) {
|
||||
CSVValue v = new CSVValue();
|
||||
v.setValidator(validator);
|
||||
v.setValue(value);
|
||||
v.setColumn(column);
|
||||
v.setRowNumber(rowNumber);
|
||||
columns.put(column, new SimpleObjectProperty<>(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -29,7 +29,6 @@ package ninja.javafx.smartcsv.fx.table.model;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
import ninja.javafx.smartcsv.validation.Validator;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public class CSVValue {
|
||||
private Validator validator;
|
||||
private int rowNumber;
|
||||
private String column;
|
||||
private StringProperty value = new SimpleStringProperty();
|
||||
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
|
||||
* @return the real value
|
||||
@@ -88,9 +60,6 @@ public class CSVValue {
|
||||
* @param value the real value
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
if (validator != null) {
|
||||
valid = validator.isValid(column, value, rowNumber);
|
||||
}
|
||||
this.value.set(value);
|
||||
}
|
||||
|
||||
@@ -106,7 +75,7 @@ public class CSVValue {
|
||||
* sets the state if a value is valid or not
|
||||
* @param valid the validation state
|
||||
*/
|
||||
protected void setValidationError(ValidationError valid) {
|
||||
public void setValidationError(ValidationError valid) {
|
||||
this.valid = valid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 javafx.ninja <info@javafx.ninja>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.fx.util;
|
||||
|
||||
/**
|
||||
* Collection of all the important colors
|
||||
*/
|
||||
public class ColorConstants {
|
||||
public static final String OK_COLOR = "#22aa22";
|
||||
public static final String ERROR_COLOR = "#ff3333";
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -40,22 +40,44 @@ import static java.text.MessageFormat.format;
|
||||
*/
|
||||
public class I18nValidationUtil {
|
||||
|
||||
public static String getI18nValidatioMessage(ResourceBundle resourceBundle, List<ValidationError> errors) {
|
||||
|
||||
StringWriter message = new StringWriter();
|
||||
errors.forEach(error -> message.append(getI18nValidatioMessage(resourceBundle, error)).append("\n"));
|
||||
|
||||
|
||||
if (message.toString().length() != 0) {
|
||||
return cutOffLastLineBreak(message.toString());
|
||||
}
|
||||
|
||||
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) {
|
||||
return getI18nValidatioMessage(resourceBundle, error, "");
|
||||
}
|
||||
|
||||
private static String getI18nValidatioMessage(ResourceBundle resourceBundle, ValidationError error, String prefix) {
|
||||
|
||||
List<ValidationMessage> validationMessages = error.getMessages();
|
||||
StringWriter message = new StringWriter();
|
||||
for (ValidationMessage validationMessage: validationMessages) {
|
||||
validationMessages.forEach(validationMessage -> {
|
||||
message.append(prefix);
|
||||
if (resourceBundle.containsKey(validationMessage.getKey())) {
|
||||
String resourceText = resourceBundle.getString(validationMessage.getKey());
|
||||
if (validationMessage.getParameters().length > 0) {
|
||||
message.append(format(resourceText, validationMessage.getParameters())).append("\n");
|
||||
message.append(format(resourceText, (Object[]) validationMessage.getParameters())).append("\n");
|
||||
} else {
|
||||
message.append(resourceText).append("\n");
|
||||
}
|
||||
} else {
|
||||
message.append(validationMessage.getKey()).append("\n");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!validationMessages.isEmpty()) {
|
||||
return cutOffLastLineBreak(message.toString());
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -28,9 +28,7 @@ package ninja.javafx.smartcsv.fx.util;
|
||||
|
||||
import javafx.concurrent.Service;
|
||||
import javafx.concurrent.Task;
|
||||
import ninja.javafx.smartcsv.FileReader;
|
||||
|
||||
import java.io.File;
|
||||
import ninja.javafx.smartcsv.files.FileStorage;
|
||||
|
||||
/**
|
||||
* Service class for async load of a csv file
|
||||
@@ -38,14 +36,10 @@ import java.io.File;
|
||||
@org.springframework.stereotype.Service
|
||||
public class LoadFileService extends Service {
|
||||
|
||||
private File file;
|
||||
private FileReader fileReader;
|
||||
private FileStorage file;
|
||||
|
||||
public void setFile(File value) {
|
||||
file = value;
|
||||
}
|
||||
public void setFileReader(FileReader fileReader) {
|
||||
this.fileReader = fileReader;
|
||||
public void setFileStorage(FileStorage file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,7 +48,7 @@ public class LoadFileService extends Service {
|
||||
@Override
|
||||
protected Void call() throws Exception {
|
||||
if (file != null) {
|
||||
fileReader.read(file);
|
||||
file.load();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -28,12 +28,7 @@ package ninja.javafx.smartcsv.fx.util;
|
||||
|
||||
import javafx.concurrent.Service;
|
||||
import javafx.concurrent.Task;
|
||||
import ninja.javafx.smartcsv.FileWriter;
|
||||
import ninja.javafx.smartcsv.csv.CSVFileWriter;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static javafx.application.Platform.runLater;
|
||||
import ninja.javafx.smartcsv.files.FileStorage;
|
||||
|
||||
/**
|
||||
* Service class for async load of a csv file
|
||||
@@ -41,14 +36,9 @@ import static javafx.application.Platform.runLater;
|
||||
@org.springframework.stereotype.Service
|
||||
public class SaveFileService extends Service {
|
||||
|
||||
private File file;
|
||||
private FileWriter writer;
|
||||
private FileStorage file;
|
||||
|
||||
public void setWriter(FileWriter writer) {
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
public void setFile(File value) {
|
||||
public void setFileStorage(FileStorage value) {
|
||||
file = value;
|
||||
}
|
||||
|
||||
@@ -58,7 +48,7 @@ public class SaveFileService extends Service {
|
||||
@Override
|
||||
protected Void call() throws Exception {
|
||||
try {
|
||||
writer.write(file);
|
||||
file.save();
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -24,47 +24,38 @@
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.fx.list;
|
||||
package ninja.javafx.smartcsv.fx.validation;
|
||||
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.scene.text.Text;
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.util.Callback;
|
||||
import ninja.javafx.smartcsv.validation.configuration.StringFormat;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static ninja.javafx.smartcsv.fx.util.I18nValidationUtil.getI18nValidatioMessage;
|
||||
|
||||
/**
|
||||
* Cell to show the error text
|
||||
* cell factory for string formats
|
||||
*/
|
||||
public class ValidationErrorListCell extends ListCell<ValidationError> {
|
||||
public class StringFormatEditorCellFactory implements Callback<ListView<StringFormat>, ListCell<StringFormat>> {
|
||||
|
||||
private ResourceBundle resourceBundle;
|
||||
|
||||
public ValidationErrorListCell(ResourceBundle resourceBundle) {
|
||||
public StringFormatEditorCellFactory(ResourceBundle resourceBundle) {
|
||||
this.resourceBundle = resourceBundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateItem(ValidationError validationError, boolean empty) {
|
||||
super.updateItem(validationError, empty);
|
||||
if (empty) {
|
||||
clearContent();
|
||||
} else {
|
||||
addContent(validationError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void clearContent() {
|
||||
setText(null);
|
||||
public ListCell<StringFormat> call(ListView<StringFormat> param) {
|
||||
return new ListCell<StringFormat>(){
|
||||
@Override
|
||||
protected void updateItem(StringFormat item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item == null || empty) {
|
||||
setGraphic(null);
|
||||
}
|
||||
|
||||
private void addContent(ValidationError validationError) {
|
||||
setText(null);
|
||||
Text text = new Text(getI18nValidatioMessage(resourceBundle, validationError));
|
||||
text.setWrappingWidth(180);
|
||||
setGraphic(text);
|
||||
} else {
|
||||
setText(resourceBundle.getString("format.type."+item));
|
||||
}
|
||||
}
|
||||
} ;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 javafx.ninja <info@javafx.ninja>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.fx.validation;
|
||||
|
||||
import javafx.util.StringConverter;
|
||||
import ninja.javafx.smartcsv.validation.configuration.StringFormat;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* converter for string formats
|
||||
*/
|
||||
public class StringFormatStringConverter extends StringConverter<StringFormat> {
|
||||
|
||||
private ResourceBundle resourceBundle;
|
||||
|
||||
public StringFormatStringConverter(ResourceBundle resourceBundle) {
|
||||
this.resourceBundle = resourceBundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(StringFormat item) {
|
||||
return resourceBundle.getString("format.type."+item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringFormat fromString(String string) {
|
||||
return StringFormat.fromExternalValue(string);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 javafx.ninja <info@javafx.ninja>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.fx.validation;
|
||||
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.SpinnerValueFactory.IntegerSpinnerValueFactory;
|
||||
import ninja.javafx.smartcsv.fx.FXMLController;
|
||||
import ninja.javafx.smartcsv.validation.configuration.*;
|
||||
import org.fxmisc.richtext.CodeArea;
|
||||
import org.fxmisc.richtext.LineNumberFactory;
|
||||
import org.fxmisc.richtext.model.StyleSpans;
|
||||
import org.fxmisc.richtext.model.StyleSpansBuilder;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static javafx.beans.binding.Bindings.when;
|
||||
import static ninja.javafx.smartcsv.validation.configuration.Type.STRING;
|
||||
|
||||
/**
|
||||
* controller for editing column validations
|
||||
*
|
||||
* RichText groovy highlighting code is based on the java example of
|
||||
* https://github.com/TomasMikula/RichTextFX
|
||||
*/
|
||||
@Component
|
||||
public class ValidationEditorController extends FXMLController {
|
||||
|
||||
private StringProperty selectedColumn = new SimpleStringProperty();
|
||||
private ValidationConfiguration validationConfiguration;
|
||||
|
||||
private static final String[] KEYWORDS = new String[] {
|
||||
"abstract", "assert", "boolean", "break", "byte",
|
||||
"case", "catch", "char", "class",
|
||||
"continue", "def", "default", "do", "double", "else",
|
||||
"enum", "extends", "false", "final", "finally", "float",
|
||||
"for", "if", "implements", "import", "in",
|
||||
"instanceof", "int", "interface", "length", "long", "native",
|
||||
"new", "null", "package", "private", "property", "protected", "public",
|
||||
"return", "short", "static", "super",
|
||||
"switch", "synchronized", "this", "threadsafe", "throw", "throws",
|
||||
"transient", "true", "try", "void", "volatile", "while"
|
||||
};
|
||||
|
||||
private static final String KEYWORD_PATTERN = "\\b(" + String.join("|", (CharSequence[]) KEYWORDS) + ")\\b";
|
||||
private static final String PAREN_PATTERN = "\\(|\\)";
|
||||
private static final String BRACE_PATTERN = "\\{|\\}";
|
||||
private static final String BRACKET_PATTERN = "\\[|\\]";
|
||||
private static final String SEMICOLON_PATTERN = "\\;";
|
||||
private static final String STRING_PATTERN = "\"([^\"\\\\]|\\\\.)*\"";
|
||||
private static final String STRING2_PATTERN = "'([^'\\\\]|\\\\.)*'";
|
||||
private static final String COMMENT_PATTERN = "//[^\n]*" + "|" + "/\\*(.|\\R)*?\\*/";
|
||||
|
||||
private static final Pattern PATTERN = Pattern.compile(
|
||||
"(?<KEYWORD>" + KEYWORD_PATTERN + ")"
|
||||
+ "|(?<PAREN>" + PAREN_PATTERN + ")"
|
||||
+ "|(?<BRACE>" + BRACE_PATTERN + ")"
|
||||
+ "|(?<BRACKET>" + BRACKET_PATTERN + ")"
|
||||
+ "|(?<SEMICOLON>" + SEMICOLON_PATTERN + ")"
|
||||
+ "|(?<STRING>" + STRING_PATTERN + ")"
|
||||
+ "|(?<STRING2>" + STRING2_PATTERN + ")"
|
||||
+ "|(?<COMMENT>" + COMMENT_PATTERN + ")"
|
||||
);
|
||||
|
||||
@FXML
|
||||
private ComboBox<Type> typeComboBox;
|
||||
|
||||
@FXML
|
||||
private ComboBox<StringFormat> formatComboBox;
|
||||
|
||||
@FXML
|
||||
private TextField formatTextField;
|
||||
|
||||
@FXML
|
||||
private Spinner<Integer> minLengthSpinner;
|
||||
|
||||
@FXML
|
||||
private Spinner<Integer> maxLengthSpinner;
|
||||
|
||||
@FXML
|
||||
private TextField regexpRuleTextField;
|
||||
|
||||
@FXML
|
||||
private TextField valueOfRuleTextField;
|
||||
|
||||
@FXML
|
||||
private CodeArea groovyRuleTextArea;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableNotEmptyRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableMinLengthRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableMaxLengthRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableRegexpRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableValueOfRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableGroovyRule;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableUniqueRule;
|
||||
|
||||
|
||||
@Value("${fxml.smartcvs.validation.editor.view}")
|
||||
@Override
|
||||
public void setFxmlFilePath(String filePath) {
|
||||
this.fxmlFilePath = filePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
initTypeAndFormatInput(resources);
|
||||
initMinMaxSpinner();
|
||||
initSpinner(minLengthSpinner, enableMinLengthRule);
|
||||
initSpinner(maxLengthSpinner, enableMaxLengthRule);
|
||||
initTextInputControl(regexpRuleTextField, enableRegexpRule);
|
||||
initTextInputControl(valueOfRuleTextField, enableValueOfRule);
|
||||
initCodeAreaControl(groovyRuleTextArea, enableGroovyRule);
|
||||
}
|
||||
|
||||
public String getSelectedColumn() {
|
||||
return selectedColumn.get();
|
||||
}
|
||||
|
||||
public StringProperty selectedColumnProperty() {
|
||||
return selectedColumn;
|
||||
}
|
||||
|
||||
public void setSelectedColumn(String selectedColumn) {
|
||||
this.selectedColumn.set(selectedColumn);
|
||||
}
|
||||
|
||||
public void setValidationConfiguration(ValidationConfiguration validationConfiguration) {
|
||||
this.validationConfiguration = validationConfiguration;
|
||||
}
|
||||
|
||||
private void initTypeAndFormatInput(ResourceBundle resources) {
|
||||
typeComboBox.getItems().addAll(STRING,
|
||||
Type.INTEGER,
|
||||
Type.NUMBER,
|
||||
Type.DATE,
|
||||
Type.DATETIME,
|
||||
Type.TIME);
|
||||
formatComboBox.setCellFactory(new StringFormatEditorCellFactory(resources));
|
||||
formatComboBox.setConverter(new StringFormatStringConverter(resources));
|
||||
formatComboBox.getItems().addAll(
|
||||
StringFormat.DEFAULT,
|
||||
StringFormat.EMAIL,
|
||||
StringFormat.URI,
|
||||
StringFormat.BINARY,
|
||||
StringFormat.UUID
|
||||
);
|
||||
typeComboBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> changeFormat());
|
||||
}
|
||||
|
||||
private void updateFormatTextField() {
|
||||
switch (typeComboBox.getValue()) {
|
||||
case DATE:
|
||||
case DATETIME:
|
||||
case TIME:
|
||||
formatTextField.setVisible(true);
|
||||
formatTextField.setText(getCurrentFieldConfig().getFormat());
|
||||
break;
|
||||
default:
|
||||
formatTextField.setVisible(false);
|
||||
formatTextField.setText(null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFormatComboBox() {
|
||||
switch (typeComboBox.getValue()) {
|
||||
case STRING:
|
||||
formatComboBox.setVisible(true);
|
||||
formatComboBox.getSelectionModel().select(StringFormat.fromExternalValue(getCurrentFieldConfig().getFormat()));
|
||||
break;
|
||||
default:
|
||||
formatComboBox.setVisible(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void initMinMaxSpinner() {
|
||||
IntegerSpinnerValueFactory minValueFactory = new IntegerSpinnerValueFactory(0, Integer.MAX_VALUE, 0);
|
||||
minLengthSpinner.setValueFactory(minValueFactory);
|
||||
IntegerSpinnerValueFactory maxValueFactory = new IntegerSpinnerValueFactory(0, Integer.MAX_VALUE, 0);
|
||||
maxLengthSpinner.setValueFactory(maxValueFactory);
|
||||
|
||||
minValueFactory.maxProperty().bind(
|
||||
when(enableMaxLengthRule.selectedProperty()).
|
||||
then(maxLengthSpinner.valueProperty()).
|
||||
otherwise(Integer.MAX_VALUE));
|
||||
maxValueFactory.minProperty().bind(
|
||||
when(enableMinLengthRule.selectedProperty()).
|
||||
then(minLengthSpinner.valueProperty()).
|
||||
otherwise(0));
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void changeFormat() {
|
||||
switch (typeComboBox.getValue()) {
|
||||
case STRING:
|
||||
updateFormatComboBox();
|
||||
break;
|
||||
case DATE:
|
||||
case DATETIME:
|
||||
case TIME:
|
||||
updateFormatTextField();
|
||||
break;
|
||||
case INTEGER:
|
||||
case NUMBER:
|
||||
default:
|
||||
// format: no options
|
||||
formatComboBox.setVisible(false);
|
||||
formatTextField.setVisible(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateConfiguration() {
|
||||
|
||||
Field config = getCurrentFieldConfig();
|
||||
config.setType(typeComboBox.getValue());
|
||||
|
||||
switch (typeComboBox.getValue()) {
|
||||
case STRING:
|
||||
config.setFormat(formatComboBox.getValue().getExternalValue());
|
||||
break;
|
||||
case DATE:
|
||||
case DATETIME:
|
||||
case TIME:
|
||||
if (formatTextField.getText().trim().isEmpty()) {
|
||||
config.setFormat(null);
|
||||
} else {
|
||||
// TODO: validate input
|
||||
config.setFormat(formatTextField.getText());
|
||||
}
|
||||
break;
|
||||
case INTEGER:
|
||||
case NUMBER:
|
||||
default:
|
||||
// format: no options
|
||||
config.setFormat(null);
|
||||
break;
|
||||
}
|
||||
|
||||
if (enableGroovyRule.isSelected()) {
|
||||
config.setGroovy(groovyRuleTextArea.getText());
|
||||
} else {
|
||||
config.setGroovy(null);
|
||||
}
|
||||
|
||||
Constraints constraints = config.getConstraints();
|
||||
if (constraints == null) {
|
||||
constraints = new Constraints();
|
||||
config.setConstraints(constraints);
|
||||
}
|
||||
|
||||
if (enableNotEmptyRule.isSelected()) {
|
||||
constraints.setRequired(enableNotEmptyRule.isSelected());
|
||||
} else {
|
||||
constraints.setRequired(null);
|
||||
}
|
||||
|
||||
if (enableUniqueRule.isSelected()) {
|
||||
constraints.setUnique(enableUniqueRule.isSelected());
|
||||
} else {
|
||||
constraints.setUnique(null);
|
||||
}
|
||||
|
||||
if (enableMinLengthRule.isSelected()) {
|
||||
constraints.setMinLength(minLengthSpinner.getValue());
|
||||
} else {
|
||||
constraints.setMinLength(null);
|
||||
}
|
||||
|
||||
if (enableMaxLengthRule.isSelected()) {
|
||||
constraints.setMaxLength(maxLengthSpinner.getValue());
|
||||
} else {
|
||||
constraints.setMaxLength(null);
|
||||
}
|
||||
|
||||
if (enableRegexpRule.isSelected()) {
|
||||
constraints.setPattern(regexpRuleTextField.getText());
|
||||
} else {
|
||||
constraints.setPattern(null);
|
||||
}
|
||||
|
||||
if (enableValueOfRule.isSelected()) {
|
||||
constraints.setEnumeration(asList(valueOfRuleTextField.getText().split(", ")));
|
||||
} else {
|
||||
constraints.setEnumeration(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Field getCurrentFieldConfig() {
|
||||
return validationConfiguration.getFieldConfiguration(getSelectedColumn());
|
||||
}
|
||||
|
||||
private void addDependencyListener(CheckBox rule, CheckBox... dependentRules) {
|
||||
rule.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
for (CheckBox dependentRule: dependentRules) {
|
||||
dependentRule.selectedProperty().setValue(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void updateForm() {
|
||||
|
||||
Field config = getCurrentFieldConfig();
|
||||
|
||||
if (config.getType() != null) {
|
||||
typeComboBox.setValue(config.getType());
|
||||
} else {
|
||||
typeComboBox.setValue(STRING);
|
||||
}
|
||||
|
||||
updateFormatComboBox();
|
||||
updateFormatTextField();
|
||||
|
||||
updateCodeAreaControl(
|
||||
groovyRuleTextArea,
|
||||
config.getGroovy(),
|
||||
enableGroovyRule
|
||||
);
|
||||
|
||||
Constraints constraints = config.getConstraints();
|
||||
updateCheckBox(constraints != null ? constraints.getRequired() : FALSE, enableNotEmptyRule);
|
||||
updateCheckBox(constraints != null ? constraints.getUnique() : FALSE, enableUniqueRule);
|
||||
|
||||
updateSpinner(
|
||||
minLengthSpinner,
|
||||
constraints != null ? constraints.getMinLength() : null,
|
||||
enableMinLengthRule
|
||||
);
|
||||
|
||||
updateSpinner(
|
||||
maxLengthSpinner,
|
||||
constraints != null ? constraints.getMaxLength() : null,
|
||||
enableMaxLengthRule
|
||||
);
|
||||
|
||||
updateTextInputControl(
|
||||
regexpRuleTextField,
|
||||
constraints != null ? constraints.getPattern() : null,
|
||||
enableRegexpRule
|
||||
);
|
||||
|
||||
updateTextInputControl(
|
||||
valueOfRuleTextField,
|
||||
constraints != null ? constraints.getEnumeration() : null,
|
||||
enableValueOfRule
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void updateCheckBox(Boolean value, CheckBox ruleEnabled) {
|
||||
if (value == null) {
|
||||
ruleEnabled.setSelected(false);
|
||||
} else {
|
||||
ruleEnabled.setSelected(value);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSpinner(Spinner rule, Integer value, CheckBox ruleEnabled) {
|
||||
if (value == null) {
|
||||
ruleEnabled.setSelected(false);
|
||||
} else {
|
||||
ruleEnabled.setSelected(true);
|
||||
rule.getValueFactory().setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTextInputControl(TextInputControl rule, String value, CheckBox ruleEnabled) {
|
||||
if (value == null) {
|
||||
ruleEnabled.setSelected(false);
|
||||
} else {
|
||||
ruleEnabled.setSelected(true);
|
||||
rule.setText(value);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTextInputControl(TextInputControl rule, List<String> values, CheckBox ruleEnabled) {
|
||||
if (values == null || values.isEmpty()) {
|
||||
ruleEnabled.setSelected(false);
|
||||
} else {
|
||||
ruleEnabled.setSelected(true);
|
||||
rule.setText(values.stream().collect(joining(", ")));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCodeAreaControl(CodeArea rule, String value, CheckBox ruleEnabled) {
|
||||
if (value == null) {
|
||||
ruleEnabled.setSelected(false);
|
||||
} else {
|
||||
ruleEnabled.setSelected(true);
|
||||
rule.replaceText(0, rule.getLength(), value);
|
||||
}
|
||||
}
|
||||
|
||||
private void initSpinner(Spinner rule, CheckBox ruleEnabled) {
|
||||
rule.disableProperty().bind(ruleEnabled.selectedProperty().not());
|
||||
ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
rule.getValueFactory().setValue(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initTextInputControl(TextInputControl rule, CheckBox ruleEnabled) {
|
||||
rule.disableProperty().bind(ruleEnabled.selectedProperty().not());
|
||||
ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
rule.setText("");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initCodeAreaControl(CodeArea rule, CheckBox ruleEnabled) {
|
||||
rule.disableProperty().bind(ruleEnabled.selectedProperty().not());
|
||||
ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
rule.clear();
|
||||
}
|
||||
});
|
||||
rule.setParagraphGraphicFactory(LineNumberFactory.get(rule));
|
||||
rule.richChanges()
|
||||
.filter(ch -> !ch.getInserted().equals(ch.getRemoved())) // XXX
|
||||
.subscribe(change -> {
|
||||
rule.setStyleSpans(0, computeHighlighting(rule.getText()));
|
||||
});
|
||||
}
|
||||
|
||||
private static StyleSpans<Collection<String>> computeHighlighting(String text) {
|
||||
Matcher matcher = PATTERN.matcher(text);
|
||||
int lastKwEnd = 0;
|
||||
StyleSpansBuilder<Collection<String>> spansBuilder
|
||||
= new StyleSpansBuilder<>();
|
||||
while(matcher.find()) {
|
||||
String styleClass =
|
||||
matcher.group("KEYWORD") != null ? "keyword" :
|
||||
matcher.group("PAREN") != null ? "paren" :
|
||||
matcher.group("BRACE") != null ? "brace" :
|
||||
matcher.group("BRACKET") != null ? "bracket" :
|
||||
matcher.group("SEMICOLON") != null ? "semicolon" :
|
||||
matcher.group("STRING") != null ? "string" :
|
||||
matcher.group("STRING2") != null ? "string" :
|
||||
matcher.group("COMMENT") != null ? "comment" :
|
||||
null; /* never happens */ assert styleClass != null;
|
||||
spansBuilder.add(Collections.emptyList(), matcher.start() - lastKwEnd);
|
||||
spansBuilder.add(Collections.singleton(styleClass), matcher.end() - matcher.start());
|
||||
lastKwEnd = matcher.end();
|
||||
}
|
||||
spansBuilder.add(Collections.emptyList(), text.length() - lastKwEnd);
|
||||
return spansBuilder.create();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -26,25 +26,24 @@
|
||||
|
||||
package ninja.javafx.smartcsv.preferences;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import ninja.javafx.smartcsv.FileReader;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.supercsv.prefs.CsvPreference;
|
||||
import org.supercsv.quote.AlwaysQuoteMode;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static ninja.javafx.smartcsv.preferences.QuoteModeHelper.getQuoteMode;
|
||||
|
||||
/**
|
||||
* file reader for the preferences
|
||||
*/
|
||||
@Service
|
||||
public class PreferencesFileReader implements FileReader {
|
||||
public class PreferencesFileReader implements FileReader<CsvPreference> {
|
||||
|
||||
private Config config;
|
||||
private Map config;
|
||||
private CsvPreference csvPreference;
|
||||
|
||||
public PreferencesFileReader() {
|
||||
@@ -55,15 +54,15 @@ public class PreferencesFileReader implements FileReader {
|
||||
|
||||
@Override
|
||||
public void read(File filename) throws IOException {
|
||||
config = ConfigFactory.parseFile(filename);
|
||||
config = new GsonBuilder().create().fromJson(new java.io.FileReader(filename), HashMap.class);
|
||||
|
||||
if (config != null) {
|
||||
char quoteChar = config.getString("quoteChar").charAt(0);
|
||||
char delimiterChar = config.getString("delimiterChar").charAt(0);
|
||||
String endOfLineSymbols = config.getString("endOfLineSymbols");
|
||||
boolean surroundingSpacesNeedQuotes = config.getBoolean("surroundingSpacesNeedQuotes");
|
||||
boolean ignoreEmptyLines = config.getBoolean("ignoreEmptyLines");
|
||||
String quoteMode = config.getString("quoteMode");
|
||||
char quoteChar = config.get("quoteChar").toString().charAt(0);
|
||||
char delimiterChar = config.get("delimiterChar").toString().charAt(0);
|
||||
String endOfLineSymbols = config.get("endOfLineSymbols").toString();
|
||||
boolean surroundingSpacesNeedQuotes = (Boolean)config.get("surroundingSpacesNeedQuotes");
|
||||
boolean ignoreEmptyLines = (Boolean)config.get("ignoreEmptyLines");
|
||||
String quoteMode = config.get("quoteMode").toString();
|
||||
|
||||
csvPreference = new CsvPreference.Builder(quoteChar, delimiterChar, endOfLineSymbols)
|
||||
.useQuoteMode(getQuoteMode(quoteMode))
|
||||
@@ -73,7 +72,7 @@ public class PreferencesFileReader implements FileReader {
|
||||
}
|
||||
}
|
||||
|
||||
public CsvPreference getCSVpreference() {
|
||||
public CsvPreference getContent() {
|
||||
return csvPreference;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -26,11 +26,9 @@
|
||||
|
||||
package ninja.javafx.smartcsv.preferences;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import com.typesafe.config.ConfigRenderOptions;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import ninja.javafx.smartcsv.FileWriter;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.supercsv.prefs.CsvPreference;
|
||||
|
||||
import java.io.File;
|
||||
@@ -42,12 +40,11 @@ import java.util.Map;
|
||||
/**
|
||||
* Save preferences to configuration file
|
||||
*/
|
||||
@Service
|
||||
public class PreferencesFileWriter implements FileWriter {
|
||||
public class PreferencesFileWriter implements FileWriter<CsvPreference> {
|
||||
|
||||
private CsvPreference csvPreference;
|
||||
|
||||
public void setCsvPreference(CsvPreference csvPreference) {
|
||||
public void setContent(CsvPreference csvPreference) {
|
||||
this.csvPreference = csvPreference;
|
||||
}
|
||||
|
||||
@@ -60,8 +57,8 @@ public class PreferencesFileWriter implements FileWriter {
|
||||
preferences.put("ignoreEmptyLines", csvPreference.isIgnoreEmptyLines());
|
||||
preferences.put("quoteMode", QuoteModeHelper.getQuoteModeName(csvPreference.getQuoteMode()));
|
||||
|
||||
Config config = ConfigFactory.parseMap(preferences);
|
||||
Files.write(file.toPath(), config.root().render(ConfigRenderOptions.concise()).getBytes());
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
Files.write(file.toPath(), gson.toJson(preferences).getBytes());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -38,6 +38,7 @@ public class ValidationError {
|
||||
|
||||
private List<ValidationMessage> messages = new ArrayList<>();
|
||||
private Integer lineNumber;
|
||||
private String column = "";
|
||||
|
||||
private ValidationError(Integer lineNumber) {
|
||||
this.lineNumber = lineNumber;
|
||||
@@ -51,10 +52,19 @@ public class ValidationError {
|
||||
return new ValidationError(-1);
|
||||
}
|
||||
|
||||
public ValidationError column(String column) {
|
||||
this.column = column;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getLineNumber() {
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
public String getColumn() {
|
||||
return column;
|
||||
}
|
||||
|
||||
public List<ValidationMessage> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -26,28 +26,53 @@
|
||||
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import ninja.javafx.smartcsv.FileReader;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ninja.javafx.smartcsv.validation.configuration.Field;
|
||||
import ninja.javafx.smartcsv.validation.configuration.ValidationConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static ninja.javafx.smartcsv.validation.configuration.Type.*;
|
||||
|
||||
/**
|
||||
* This class loads the constraints as json config
|
||||
*/
|
||||
@Service
|
||||
public class ValidationFileReader implements FileReader {
|
||||
public class ValidationFileReader implements FileReader<ValidationConfiguration> {
|
||||
|
||||
private Config config;
|
||||
private ValidationConfiguration config;
|
||||
|
||||
@Override
|
||||
public void read(File file) throws IOException {
|
||||
config = ConfigFactory.parseFile(file);
|
||||
config = new GsonBuilder().create().fromJson(new java.io.FileReader(file), ValidationConfiguration.class);
|
||||
setDefaults();
|
||||
}
|
||||
|
||||
public Validator getValidator() {
|
||||
return new Validator(config);
|
||||
private void setDefaults() {
|
||||
for (Field field : config.getFields()) {
|
||||
if (field.getType() == null) {
|
||||
field.setType(STRING);
|
||||
}
|
||||
if (field.getType() == DATE) {
|
||||
if (field.getFormat() == null) {
|
||||
field.setFormat("yyyy-MM-dd");
|
||||
}
|
||||
}
|
||||
if (field.getType() == DATETIME) {
|
||||
if (field.getFormat() == null) {
|
||||
field.setFormat("yyyy-MM-ddThh:mm:ssZ");
|
||||
}
|
||||
}
|
||||
if (field.getType() == TIME) {
|
||||
if (field.getFormat() == null) {
|
||||
field.setFormat("hh:mm:ss");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ValidationConfiguration getContent() {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 javafx.ninja <info@javafx.ninja>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import ninja.javafx.smartcsv.FileWriter;
|
||||
import ninja.javafx.smartcsv.validation.configuration.ValidationConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
/**
|
||||
* file writer for the validation configuration
|
||||
*/
|
||||
public class ValidationFileWriter implements FileWriter<ValidationConfiguration> {
|
||||
|
||||
private ValidationConfiguration validationConfiguration;
|
||||
|
||||
public void setContent(ValidationConfiguration validationConfiguration) {
|
||||
this.validationConfiguration = validationConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(File file) throws IOException {
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
Files.write(file.toPath(), gson.toJson(validationConfiguration).getBytes());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
/**
|
||||
* @author abi
|
||||
*/
|
||||
public class ValidationFormatHelper {
|
||||
|
||||
|
||||
public static String dateFormat(String format, String defaultFormat) {
|
||||
|
||||
if (format != null && !format.trim().isEmpty()) {
|
||||
format = format.trim();
|
||||
if (format.startsWith("fmt:")) {
|
||||
format = format.substring(4);
|
||||
format = format.replace("%Y", "yyyy");
|
||||
format = format.replace("%y", "yy");
|
||||
format = format.replace("%m", "MM");
|
||||
format = format.replace("%d", "dd");
|
||||
format = format.replace("%a", "E");
|
||||
format = format.replace("%A", "EEEE");
|
||||
format = format.replace("%w", "F");
|
||||
format = format.replace("%b", "MMM");
|
||||
format = format.replace("%B", "MMMMM");
|
||||
format = format.replace("%H", "HH");
|
||||
format = format.replace("%I", "hh");
|
||||
format = format.replace("%p", "a");
|
||||
format = format.replace("%M", "mm");
|
||||
format = format.replace("%S", "ss");
|
||||
format = format.replace("%z", "Z");
|
||||
format = format.replace("%Z", "z");
|
||||
format = format.replace("%j", "DDD");
|
||||
format = format.replace("%U", "ww");
|
||||
return format;
|
||||
} else {
|
||||
try {
|
||||
new SimpleDateFormat(format);
|
||||
return format;
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultFormat;
|
||||
}
|
||||
|
||||
public static Integer doubleToInteger(Double value) {
|
||||
if (value == null) return null;
|
||||
return (int)Math.round(value);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -26,18 +26,19 @@
|
||||
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import groovy.lang.Binding;
|
||||
import groovy.lang.GroovyShell;
|
||||
import groovy.lang.Script;
|
||||
import org.codehaus.groovy.control.CompilationFailedException;
|
||||
import ninja.javafx.smartcsv.fx.table.model.ColumnValueProvider;
|
||||
import ninja.javafx.smartcsv.validation.checker.*;
|
||||
import ninja.javafx.smartcsv.validation.configuration.Constraints;
|
||||
import ninja.javafx.smartcsv.validation.configuration.Field;
|
||||
import ninja.javafx.smartcsv.validation.configuration.ValidationConfiguration;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static org.apache.commons.validator.GenericValidator.*;
|
||||
import static ninja.javafx.smartcsv.validation.ValidationFormatHelper.dateFormat;
|
||||
import static ninja.javafx.smartcsv.validation.configuration.StringFormat.*;
|
||||
import static ninja.javafx.smartcsv.validation.configuration.Type.*;
|
||||
|
||||
/**
|
||||
* This class checks all the validations defined in the
|
||||
@@ -49,10 +50,9 @@ public class Validator {
|
||||
// member variables
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private Config validationConfig;
|
||||
private GroovyShell shell = new GroovyShell();
|
||||
private Map<String, Script> scriptCache = new HashMap<>();
|
||||
|
||||
private ValidationConfiguration validationConfig;
|
||||
private ColumnValueProvider columnValueProvider;
|
||||
private Map<String, Map<Validation.Type, Validation>> columnValidationMap = new HashMap<>();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructors
|
||||
@@ -60,221 +60,227 @@ public class Validator {
|
||||
|
||||
/**
|
||||
* JSON configuration for this validator
|
||||
*
|
||||
* @param validationConfig
|
||||
*/
|
||||
public Validator(Config validationConfig) {
|
||||
public Validator(ValidationConfiguration validationConfig, ColumnValueProvider columnValueProvider) {
|
||||
this.validationConfig = validationConfig;
|
||||
this.columnValueProvider = columnValueProvider;
|
||||
initColumnValidations();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// oublic 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
|
||||
*
|
||||
* @param column the column name
|
||||
* @param value the value to check
|
||||
* @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;
|
||||
if (validationConfig != null) {
|
||||
Config columnSectionConfig = getColumnSectionConfig();
|
||||
if (columnSectionConfig != null) {
|
||||
Config columnConfig = getColumnConfig(columnSectionConfig, column);
|
||||
if (columnConfig != null) {
|
||||
|
||||
ValidationError error = ValidationError.withLineNumber(lineNumber);
|
||||
checkBlankOrNull(columnConfig, value, error);
|
||||
if (value != null && !value.isEmpty()) {
|
||||
checkRegularExpression(columnConfig, value, error);
|
||||
checkAlphaNumeric(columnConfig, value, error);
|
||||
checkDate(columnConfig, value, error);
|
||||
checkMaxLength(columnConfig, value, error);
|
||||
checkMinLength(columnConfig, value, error);
|
||||
checkInteger(columnConfig, value, error);
|
||||
checkGroovy(column, columnConfig, value, error);
|
||||
checkValueOf(columnConfig, value, error);
|
||||
checkDouble(columnConfig, value, error);
|
||||
if (hasConfig()) {
|
||||
ValidationError error = ValidationError.withLineNumber(row).column(column);
|
||||
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
|
||||
if (validationMap != null) {
|
||||
for (Validation validation: validationMap.values()) {
|
||||
if (validation.canBeChecked(value)) {
|
||||
validation.check(row, value, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!error.isEmpty()) {
|
||||
result = error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public boolean hasConfig() {
|
||||
return validationConfig != null;
|
||||
}
|
||||
|
||||
public void reinitializeColumn(String column) {
|
||||
clear(column);
|
||||
initializeColumnWithRules(column);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// private methods
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void checkGroovy(String column, Config columnConfig, String value, ValidationError error) {
|
||||
String groovyScript = getString(columnConfig, "groovy");
|
||||
if (groovyScript != null) {
|
||||
|
||||
Script script = scriptCache.get(column);
|
||||
if (script == null) {
|
||||
script = shell.parse(groovyScript);
|
||||
scriptCache.put(column, script);
|
||||
private void add(String column, Validation validation) {
|
||||
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
|
||||
if (validationMap == null) {
|
||||
validationMap = new HashMap<>();
|
||||
columnValidationMap.put(column, validationMap);
|
||||
}
|
||||
validationMap.put(validation.getType(), validation);
|
||||
}
|
||||
|
||||
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();
|
||||
private void remove(String column, Validation.Type type) {
|
||||
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
|
||||
if (validationMap == null) {
|
||||
validationMap = new HashMap<>();
|
||||
columnValidationMap.put(column, validationMap);
|
||||
}
|
||||
if (groovyResult == null) {
|
||||
error.add("validation.message.groovy.return.null", groovyScript);
|
||||
validationMap.remove(type);
|
||||
}
|
||||
|
||||
if (!isScriptResultTrue(groovyResult)) {
|
||||
error.add(groovyResult.toString());
|
||||
private void clear(String column) {
|
||||
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
|
||||
if (validationMap != null) {
|
||||
validationMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void initColumnValidations() {
|
||||
if (hasConfig()) {
|
||||
for (Field column : validationConfig.getFields()) {
|
||||
initializeColumnWithRules(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeColumnWithRules(String columnName) {
|
||||
if (hasConfig()) {
|
||||
for (Field column : validationConfig.getFields()) {
|
||||
if (column.getName().equals(columnName)) {
|
||||
initializeColumnWithRules(column);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initializeColumnWithRules(Field column) {
|
||||
|
||||
if (column.getType() != null) {
|
||||
if (column.getType() == NUMBER) {
|
||||
add(column.getName(), new DoubleValidation());
|
||||
}
|
||||
|
||||
if (column.getType() == INTEGER) {
|
||||
add(column.getName(), new IntegerValidation());
|
||||
}
|
||||
|
||||
if (column.getType() == DATE) {
|
||||
String format = dateFormat(column.getFormat(), "yyyy-MM-dd");
|
||||
add(column.getName(), new DateValidation(format));
|
||||
}
|
||||
|
||||
if (column.getType() == DATETIME) {
|
||||
String format = dateFormat(column.getFormat(), "yyyy-MM-ddThh:mm:ssZ");
|
||||
add(column.getName(), new DateValidation(format));
|
||||
}
|
||||
|
||||
if (column.getType() == TIME) {
|
||||
String format = dateFormat(column.getFormat(), "hh:mm:ss");
|
||||
add(column.getName(), new DateValidation(format));
|
||||
}
|
||||
|
||||
if (column.getType() == STRING && column.getFormat() == null) {
|
||||
remove(column.getName(), Validation.Type.STRING);
|
||||
} else {
|
||||
|
||||
if (column.getType() == STRING && column.getFormat().equalsIgnoreCase(EMAIL.getExternalValue())) {
|
||||
add(column.getName(), new EmailValidation());
|
||||
}
|
||||
|
||||
if (column.getType() == STRING && column.getFormat().equalsIgnoreCase(URI.getExternalValue())) {
|
||||
add(column.getName(), new UriValidation());
|
||||
}
|
||||
|
||||
if (column.getType() == STRING && column.getFormat().equalsIgnoreCase(UUID.getExternalValue())) {
|
||||
add(column.getName(), new UuidValidation());
|
||||
}
|
||||
|
||||
if (column.getType() == STRING && column.getFormat().equalsIgnoreCase(BINARY.getExternalValue())) {
|
||||
add(column.getName(), new BinaryValidation());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isScriptResultTrue(Object groovyResult) {
|
||||
return groovyResult.equals(true) || groovyResult.toString().trim().toLowerCase().equals("true");
|
||||
String groovy = column.getGroovy();
|
||||
if (groovy != null && !groovy.trim().isEmpty()) {
|
||||
add(column.getName(), new GroovyValidation(groovy));
|
||||
}
|
||||
|
||||
private void checkValueOf(Config columnConfig, String value, ValidationError error) {
|
||||
List<String> stringList = getStringList(columnConfig, "value of");
|
||||
if (stringList != null) {
|
||||
if (!stringList.contains(value)) {
|
||||
String commaSeparated = stringList.stream().collect(joining(", "));
|
||||
error.add("validation.message.value.of", value, commaSeparated);
|
||||
}
|
||||
}
|
||||
Constraints constraints = column.getConstraints();
|
||||
if (constraints != null) {
|
||||
Boolean notEmptyRule = constraints.getRequired();
|
||||
if (notEmptyRule != null && notEmptyRule) {
|
||||
add(column.getName(), new NotEmptyValidation());
|
||||
}
|
||||
|
||||
private void checkBlankOrNull(Config columnConfig, String value, ValidationError error) {
|
||||
if (getBoolean(columnConfig, "not empty")) {
|
||||
if (isBlankOrNull(value)) {
|
||||
error.add("validation.message.not.empty");
|
||||
}
|
||||
}
|
||||
Boolean uniqueRule = constraints.getUnique();
|
||||
if (uniqueRule != null && uniqueRule) {
|
||||
add(column.getName(), new UniqueValidation(columnValueProvider, column.getName()));
|
||||
}
|
||||
|
||||
private void checkInteger(Config columnConfig, String value, ValidationError error) {
|
||||
if (getBoolean(columnConfig, "integer")) {
|
||||
if (!isInt(value)) {
|
||||
error.add("validation.message.integer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDouble(Config columnConfig, String value, ValidationError error) {
|
||||
if (getBoolean(columnConfig, "double")) {
|
||||
if (!isDouble(value)) {
|
||||
error.add("validation.message.double");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void checkMinLength(Config columnConfig, String value, ValidationError error) {
|
||||
Integer minLength = getInteger(columnConfig, "minlength");
|
||||
Integer minLength = constraints.getMinLength();
|
||||
if (minLength != null) {
|
||||
if (!minLength(value, minLength)) {
|
||||
error.add("validation.message.min.length", minLength.toString());
|
||||
}
|
||||
}
|
||||
add(column.getName(), new MinLengthValidation(minLength));
|
||||
}
|
||||
|
||||
private void checkMaxLength(Config columnConfig, String value, ValidationError error) {
|
||||
Integer maxLength = getInteger(columnConfig, "maxlength");
|
||||
Integer maxLength = constraints.getMaxLength();
|
||||
if (maxLength != null) {
|
||||
if (!maxLength(value, maxLength)) {
|
||||
error.add("validation.message.max.length", maxLength.toString());
|
||||
}
|
||||
}
|
||||
add(column.getName(), new MaxLengthValidation(maxLength));
|
||||
}
|
||||
|
||||
private void checkDate(Config columnConfig, String value, ValidationError error) {
|
||||
String dateformat = getString(columnConfig, "date");
|
||||
if (dateformat != null && !dateformat.trim().isEmpty()) {
|
||||
if (!isDate(value, dateformat, true)) {
|
||||
error.add("validation.message.date.format", dateformat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAlphaNumeric(Config columnConfig, String value, ValidationError error) {
|
||||
if (getBoolean(columnConfig, "alphanumeric")) {
|
||||
if (!matchRegexp(value, "[0-9a-zA-Z]*")) {
|
||||
error.add("validation.message.alphanumeric");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRegularExpression(Config columnConfig, String value, ValidationError error) {
|
||||
String regexp = getString(columnConfig, "regexp");
|
||||
String regexp = constraints.getPattern();
|
||||
if (regexp != null && !regexp.trim().isEmpty()) {
|
||||
if (!matchRegexp(value, regexp)) {
|
||||
error.add("validation.message.regexp", regexp);
|
||||
add(column.getName(), new RegExpValidation(regexp));
|
||||
}
|
||||
|
||||
|
||||
|
||||
List<String> valueOfRule = constraints.getEnumeration();
|
||||
if (valueOfRule != null && !valueOfRule.isEmpty()) {
|
||||
add(column.getName(), new ValueOfValidation(valueOfRule));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Config getColumnSectionConfig() {
|
||||
return validationConfig.hasPath("columns") ? validationConfig.getConfig("columns") : null;
|
||||
}
|
||||
|
||||
private Config getColumnConfig(Config columnSectionConfig, String column) {
|
||||
return columnSectionConfig.hasPath(column) ? columnSectionConfig.getConfig(column) : null;
|
||||
}
|
||||
|
||||
|
||||
private String getString(Config columnConfig, String path) {
|
||||
return columnConfig.hasPath(path) ? columnConfig.getString(path) : null;
|
||||
}
|
||||
|
||||
private Integer getInteger(Config columnConfig, String path) {
|
||||
return columnConfig.hasPath(path) ? columnConfig.getInt(path) : null;
|
||||
}
|
||||
|
||||
private boolean getBoolean(Config columnConfig, String path) {
|
||||
return columnConfig.hasPath(path) && columnConfig.getBoolean(path);
|
||||
}
|
||||
|
||||
private List<String> getStringList(Config columnConfig, String path) {
|
||||
return columnConfig.hasPath(path) ? columnConfig.getStringList(path) : null;
|
||||
}
|
||||
|
||||
public ValidationError isHeaderValid(String[] headerNames) {
|
||||
ValidationError result = null;
|
||||
if (validationConfig != null) {
|
||||
if (validationConfig.hasPath("headers")) {
|
||||
Config headerSectionConfig = validationConfig.getConfig("headers");
|
||||
List<String> headerConfig = getStringList(headerSectionConfig, "list");
|
||||
if (headerConfig != null) {
|
||||
if (headerNames.length != headerConfig.size()) {
|
||||
String[] headerNamesConfig = validationConfig.headerNames();
|
||||
if (headerNamesConfig != null) {
|
||||
if (headerNames.length != headerNamesConfig.length) {
|
||||
result = ValidationError.withoutLineNumber().add("validation.message.header.length",
|
||||
Integer.toString(headerNames.length),
|
||||
Integer.toString(headerConfig.size()));
|
||||
Integer.toString(headerNamesConfig.length));
|
||||
return result;
|
||||
}
|
||||
|
||||
ValidationError error = ValidationError.withoutLineNumber();
|
||||
|
||||
for(int i=0; i<headerConfig.size(); i++) {
|
||||
String header = headerConfig.get(i);
|
||||
if (!header.equals(headerNames[i])) {
|
||||
for (int i = 0; i < headerNamesConfig.length; i++) {
|
||||
if (!headerNamesConfig[i].equals(headerNames[i])) {
|
||||
error.add("validation.message.header.match",
|
||||
Integer.toString(i),
|
||||
header,
|
||||
headerNamesConfig[i],
|
||||
headerNames[i]);
|
||||
}
|
||||
}
|
||||
@@ -283,7 +289,8 @@ public class Validator {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* checks if the value is a base64 encoded string representing binary data
|
||||
*/
|
||||
public class BinaryValidation extends EmptyValueIsValid {
|
||||
|
||||
@Override
|
||||
public void check(int row, String value, ValidationError error) {
|
||||
try {
|
||||
Base64.getDecoder().decode(value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
error.add("validation.message.binary");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.STRING;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
import org.apache.commons.validator.routines.EmailValidator;
|
||||
|
||||
/**
|
||||
* checks if the value is a valid email address
|
||||
*/
|
||||
public class EmailValidation extends EmptyValueIsValid {
|
||||
|
||||
@Override
|
||||
public void check(int row, String value, ValidationError error) {
|
||||
if (!EmailValidator.getInstance().isValid(value)) {
|
||||
error.add("validation.message.email");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.STRING;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package ninja.javafx.smartcsv.validation.checker;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import groovy.lang.Binding;
|
||||
import groovy.lang.GroovyShell;
|
||||
import groovy.lang.Script;
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.fx.table.model.ColumnValueProvider;
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
/**
|
||||
* checks if the value is a valid uri address
|
||||
*/
|
||||
public class UriValidation extends EmptyValueIsValid {
|
||||
|
||||
@Override
|
||||
public void check(int row, String value, ValidationError error) {
|
||||
try {
|
||||
new URI(value);
|
||||
} catch (URISyntaxException e) {
|
||||
error.add("validation.message.uri");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.STRING;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* checks if the value is a valid uuid
|
||||
*/
|
||||
public class UuidValidation extends EmptyValueIsValid {
|
||||
|
||||
@Override
|
||||
public void check(int row, String value, ValidationError error) {
|
||||
try {
|
||||
UUID.fromString(value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
error.add("validation.message.uuid");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.STRING;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
/**
|
||||
* Interface for all validations
|
||||
*/
|
||||
public interface Validation {
|
||||
|
||||
enum Type { NOT_EMPTY, UNIQUE, DOUBLE, INTEGER, MIN_LENGTH, MAX_LENGTH, DATE, REGEXP, VALUE_OF, STRING, GROOVY }
|
||||
void check(int row, String value, ValidationError error);
|
||||
Type getType();
|
||||
boolean canBeChecked(String value);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.checker;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.configuration;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* contraints defined in JSON Table Schema
|
||||
* @see <a href="http://specs.frictionlessdata.io/json-table-schema/">JSON Table Schema</a>
|
||||
*/
|
||||
public class Constraints {
|
||||
private Boolean required;
|
||||
private Boolean unique;
|
||||
private Integer minLength;
|
||||
private Integer maxLength;
|
||||
|
||||
private String pattern;
|
||||
|
||||
@SerializedName("enum")
|
||||
private List<String> enumeration;
|
||||
|
||||
public Boolean getRequired() {
|
||||
return required;
|
||||
}
|
||||
|
||||
public void setRequired(Boolean required) {
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
public Boolean getUnique() {
|
||||
return unique;
|
||||
}
|
||||
|
||||
public void setUnique(Boolean unique) {
|
||||
this.unique = unique;
|
||||
}
|
||||
|
||||
public Integer getMinLength() {
|
||||
return minLength;
|
||||
}
|
||||
|
||||
public void setMinLength(Integer minLength) {
|
||||
this.minLength = minLength;
|
||||
}
|
||||
|
||||
public Integer getMaxLength() {
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
public void setMaxLength(Integer maxLength) {
|
||||
this.maxLength = maxLength;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public void setPattern(String pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
public List<String> getEnumeration() {
|
||||
return enumeration;
|
||||
}
|
||||
|
||||
public void setEnumeration(List<String> enumeration) {
|
||||
this.enumeration = enumeration;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.configuration;
|
||||
|
||||
/**
|
||||
* this class represents a field in the configuration
|
||||
* @see <a href="http://specs.frictionlessdata.io/json-table-schema/">JSON Table Schema</a>
|
||||
*/
|
||||
public class Field {
|
||||
|
||||
private String name;
|
||||
private String title;
|
||||
private Type type;
|
||||
private String description;
|
||||
private String format;
|
||||
private Object missingValue;
|
||||
private Constraints constraints;
|
||||
private String groovy;
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public Object getMissingValue() {
|
||||
return missingValue;
|
||||
}
|
||||
|
||||
public void setMissingValue(Object missingValue) {
|
||||
this.missingValue = missingValue;
|
||||
}
|
||||
|
||||
public Constraints getConstraints() {
|
||||
return constraints;
|
||||
}
|
||||
|
||||
public void setConstraints(Constraints constraints) {
|
||||
this.constraints = constraints;
|
||||
}
|
||||
|
||||
public String getGroovy() {
|
||||
return groovy;
|
||||
}
|
||||
|
||||
public void setGroovy(String groovy) {
|
||||
this.groovy = groovy;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.configuration;
|
||||
|
||||
/**
|
||||
* Enumeration for format values for type string in JSON Table Schema
|
||||
* @see <a href="http://specs.frictionlessdata.io/json-table-schema/">JSON Table Schema</a>
|
||||
*/
|
||||
public enum StringFormat {
|
||||
DEFAULT(null),
|
||||
EMAIL("email"),
|
||||
URI("uri"),
|
||||
BINARY("binary"),
|
||||
UUID("uuid");
|
||||
|
||||
private String externalValue;
|
||||
|
||||
StringFormat(String externalValue) {
|
||||
this.externalValue = externalValue;
|
||||
}
|
||||
|
||||
public String getExternalValue() {
|
||||
return externalValue;
|
||||
}
|
||||
|
||||
public static StringFormat fromExternalValue(String externalValue) {
|
||||
if (externalValue != null) {
|
||||
for (StringFormat value : StringFormat.values()) {
|
||||
if (externalValue.equals(value.getExternalValue())) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return DEFAULT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.configuration;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Types of JSON Table Schema
|
||||
* @see <a href="http://specs.frictionlessdata.io/json-table-schema/">JSON Table Schema</a>
|
||||
*/
|
||||
public enum Type {
|
||||
@SerializedName("string")STRING,
|
||||
@SerializedName("integer")INTEGER,
|
||||
@SerializedName("number")NUMBER,
|
||||
@SerializedName("date")DATE,
|
||||
@SerializedName("datetime")DATETIME,
|
||||
@SerializedName("time")TIME
|
||||
// TODO: currently not supported
|
||||
// @SerializedName("object") OBJECT,
|
||||
// @SerializedName("array") ARRAY,
|
||||
// @SerializedName("duration") DURATION,
|
||||
// @SerializedName("geopoint") GEOPOINT,
|
||||
// @SerializedName("geojson") GEOJSON
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2016 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.configuration;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Configuration based on JSON Table Schema
|
||||
* @see <a href="http://specs.frictionlessdata.io/json-table-schema/">JSON Table Schema</a>
|
||||
*/
|
||||
public class ValidationConfiguration {
|
||||
|
||||
@SerializedName("fields")
|
||||
private Field[] fields;
|
||||
|
||||
public Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public void setFields(Field[] fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
public Field getFieldConfiguration(String column) {
|
||||
for (Field field : fields) {
|
||||
if (field.getName().equals(column)) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String[] headerNames() {
|
||||
if (fields != null) {
|
||||
List<String> headerNames = new ArrayList<>();
|
||||
for (Field field : fields) {
|
||||
headerNames.add(field.getName());
|
||||
}
|
||||
return headerNames.toArray(new String[headerNames.size()]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setHeaderNames(String[] header) {
|
||||
fields = new Field[header.length];
|
||||
int i = 0;
|
||||
for (String headerName: header) {
|
||||
fields[i] = new Field();
|
||||
fields[i].setName(headerName);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/main/resources/log4j2.xml
Normal file
26
src/main/resources/log4j2.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="error">
|
||||
|
||||
<Properties>
|
||||
<Property name="filename">smartcsv.log</Property>
|
||||
</Properties>
|
||||
<ThresholdFilter level="trace"/>
|
||||
|
||||
<Appenders>
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
|
||||
</Console>
|
||||
|
||||
<File name="File" fileName="${filename}" bufferedIO="true">
|
||||
<PatternLayout>
|
||||
<pattern>%d %p %C{1.} [%t] %m%n</pattern>
|
||||
</PatternLayout>
|
||||
</File>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="error">
|
||||
<AppenderRef ref="File"/>
|
||||
<AppenderRef ref="Console"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
@@ -1,14 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.text.*?>
|
||||
<?import java.lang.*?>
|
||||
<?import javafx.geometry.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Hyperlink?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?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?>
|
||||
|
||||
|
||||
<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.66" 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.76-ea" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<children>
|
||||
<Label text="Thanks for contributions:">
|
||||
<font>
|
||||
<Font size="18.0" />
|
||||
</font>
|
||||
<VBox.margin>
|
||||
<Insets top="8.0" />
|
||||
</VBox.margin>
|
||||
</Label>
|
||||
<Label text="AOE Takashi (https://github.com/aoetk)" />
|
||||
<Label text="Hasan Kara (https://github.com/haisi)" />
|
||||
<Label text="3rd party software">
|
||||
<VBox.margin>
|
||||
<Insets top="8.0" />
|
||||
@@ -19,20 +33,23 @@
|
||||
</Label>
|
||||
<ScrollPane fitToHeight="true" fitToWidth="true">
|
||||
<content>
|
||||
<GridPane hgap="4.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" vgap="4.0">
|
||||
<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<Label text="junit" />
|
||||
@@ -45,12 +62,18 @@
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="https://spring.io/" GridPane.columnIndex="1" GridPane.rowIndex="3" />
|
||||
<Label text="supercsv" GridPane.rowIndex="4" />
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="http://super-csv.github.io/super-csv/" GridPane.columnIndex="1" GridPane.rowIndex="4" />
|
||||
<Label text="config" GridPane.rowIndex="5" />
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="https://github.com/typesafehub/config" GridPane.columnIndex="1" GridPane.rowIndex="5" />
|
||||
<Label text="Gson" GridPane.rowIndex="5" />
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="https://github.com/google/gson/" GridPane.columnIndex="1" GridPane.rowIndex="5" />
|
||||
<Label text="commons-validator" GridPane.rowIndex="6" />
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="https://commons.apache.org/proper/commons-validator/" GridPane.columnIndex="1" GridPane.rowIndex="6" />
|
||||
<Label text="fontawesomefx" GridPane.rowIndex="7" />
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="https://bitbucket.org/Jerady/fontawesomefx" GridPane.columnIndex="1" GridPane.rowIndex="7" />
|
||||
<Label text="ControlsFX" GridPane.rowIndex="8" />
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="http://fxexperience.com/controlsfx/" GridPane.columnIndex="1" GridPane.rowIndex="8" />
|
||||
<Label text="Apache Log4j 2" GridPane.rowIndex="9" />
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="http://logging.apache.org/log4j/2.x/" GridPane.columnIndex="1" GridPane.rowIndex="9" />
|
||||
<Label text="RichTextFX" GridPane.rowIndex="10" />
|
||||
<Hyperlink onAction="#openLinkInBrowser" text="https://github.com/TomasMikula/RichTextFX" GridPane.columnIndex="1" GridPane.rowIndex="10" />
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="4.0" left="8.0" right="8.0" top="4.0" />
|
||||
@@ -66,7 +89,7 @@
|
||||
<Font size="18.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<TextArea editable="false" prefHeight="200.0" prefWidth="200.0" text="Copyright (c) 2015 Andreas Billmann <andreas.billmann@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." wrapText="true" />
|
||||
<TextArea editable="false" prefHeight="200.0" prefWidth="200.0" text="Copyright (c) 2015-2019 Andreas Billmann <andreas.billmann@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." wrapText="true" />
|
||||
</children>
|
||||
<opaqueInsets>
|
||||
<Insets />
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
application.name = SmartCSV.fx
|
||||
application.version = 0.3
|
||||
application.version = 0.9.1
|
||||
|
||||
# fxml views
|
||||
fxml.smartcvs.view = /ninja/javafx/smartcsv/fx/smartcsv.fxml
|
||||
fxml.smartcvs.about.view = /ninja/javafx/smartcsv/fx/about/about.fxml
|
||||
fxml.smartcvs.preferences.view = /ninja/javafx/smartcsv/fx/preferences/preferences.fxml
|
||||
fxml.smartcvs.validation.editor.view = /ninja/javafx/smartcsv/fx/validation/validationEditor.fxml
|
||||
|
||||
# resources
|
||||
resource.main = ninja.javafx.smartcsv.fx.smartcsv
|
||||
@@ -1,10 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.*?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import java.lang.*?>
|
||||
<?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">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
|
||||
|
||||
@@ -1,50 +1,229 @@
|
||||
.list-view {
|
||||
.table-view .list-view {
|
||||
-fx-background-color: -fx-background;
|
||||
-fx-padding: 1;
|
||||
}
|
||||
|
||||
.list-cell {
|
||||
.table-view .list-cell {
|
||||
-fx-padding: 1.0em 1.0em 1.0em 1.0em;
|
||||
}
|
||||
.list-cell:odd {
|
||||
.table-view .list-cell:odd {
|
||||
-fx-background: -fx-control-inner-background-alt;
|
||||
}
|
||||
|
||||
.list-cell:even {
|
||||
.table-view .list-cell:even {
|
||||
-fx-background: -fx-control-inner-background;
|
||||
}
|
||||
|
||||
.open-icon {
|
||||
-glyph-name: "FILE_TEXT_ALT";
|
||||
-glyph-size: 14px;
|
||||
-glyph-name: "FILE_IMPORT";
|
||||
-glyph-size: 16px;
|
||||
}
|
||||
|
||||
.file-document-icon {
|
||||
-glyph-name: "FILE_DOCUMENT";
|
||||
-glyph-size: 16px;
|
||||
}
|
||||
|
||||
.config-icon {
|
||||
-glyph-name: "CHECK";
|
||||
-glyph-size: 14px;
|
||||
-glyph-name: "CLIPBOARD";
|
||||
-glyph-size: 16px;
|
||||
}
|
||||
|
||||
.create-config-icon {
|
||||
-glyph-name: "STAR";
|
||||
-glyph-size: 10px;
|
||||
}
|
||||
|
||||
.load-config-icon {
|
||||
-glyph-name: "ARROW_UP_BOLD";
|
||||
-glyph-size: 10px;
|
||||
}
|
||||
|
||||
.save-config-icon {
|
||||
-glyph-name: "ARROW_DOWN_BOLD";
|
||||
-glyph-size: 10px;
|
||||
}
|
||||
|
||||
.save-icon {
|
||||
-glyph-name: "FLOPPY_ALT";
|
||||
-glyph-size: 14px;
|
||||
-glyph-name: "FILE_EXPORT";
|
||||
-glyph-size: 16px;
|
||||
}
|
||||
|
||||
.exit-icon {
|
||||
-glyph-name: "SIGN_OUT";
|
||||
-glyph-size: 14px;
|
||||
-glyph-name: "EXIT_TO_APP";
|
||||
-glyph-size: 16px;
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
-glyph-name: "INFO";
|
||||
-glyph-size: 14px;
|
||||
-glyph-name: "INFORMATION_OUTLINE";
|
||||
-glyph-size: 16px;
|
||||
}
|
||||
|
||||
.error-title-icon {
|
||||
-glyph-name: "EXCLAMATION_TRIANGLE";
|
||||
-glyph-size: 14px;
|
||||
.config-check-icon {
|
||||
-glyph-name: "CLIPBOARD_CHECK";
|
||||
-glyph-size: 16px;
|
||||
}
|
||||
|
||||
.preferences-icon {
|
||||
-glyph-name: "COG";
|
||||
-glyph-size: 14px;
|
||||
-glyph-name: "SETTINGS";
|
||||
-glyph-size: 16px;
|
||||
}
|
||||
|
||||
.delete-icon {
|
||||
-glyph-name: "TABLE_ROW_REMOVE";
|
||||
-glyph-size: 16px;
|
||||
}
|
||||
|
||||
.add-icon {
|
||||
-glyph-name: "TABLE_ROW_PLUS_AFTER";
|
||||
-glyph-size: 16px;
|
||||
}
|
||||
|
||||
.goto-icon {
|
||||
-glyph-name: "SUBDIRECTORY_ARROW_RIGHT";
|
||||
-glyph-size: 16px;
|
||||
}
|
||||
|
||||
.export-icon {
|
||||
-glyph-name: "BUG";
|
||||
-glyph-size: 16px;
|
||||
}
|
||||
|
||||
|
||||
/* toolbar customization based on http://fxexperience.com/2012/02/customized-segmented-toolbar-buttons/ */
|
||||
|
||||
#background {
|
||||
-light-black: rgb(74, 75, 78);
|
||||
-dark-highlight: rgb(87, 89, 92);
|
||||
-dark-black: rgb(39, 40, 40);
|
||||
-darkest-black: rgb(5, 5, 5);
|
||||
-mid-gray: rgb(216, 222, 227);
|
||||
-fx-background-color: -mid-gray;
|
||||
}
|
||||
|
||||
.tool-bar {
|
||||
-fx-base: -dark-black;
|
||||
-fx-font-size: 12px;
|
||||
-fx-background-color:
|
||||
linear-gradient(to bottom, derive(-fx-base,-30%), derive(-fx-base,-60%)),
|
||||
linear-gradient(to bottom, -light-black 2%, -dark-black 98%);
|
||||
-fx-background-insets: 0, 0 0 1 0;
|
||||
-fx-padding: .6em 0.416667em .6em 0.416667em;
|
||||
-fx-effect: dropshadow(two-pass-box,black,5,.2,0,0);
|
||||
}
|
||||
|
||||
.tool-bar .open-icon {
|
||||
-glyph-size: 16px;
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.tool-bar .config-icon {
|
||||
-glyph-size: 16px;
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.menu-item .load-config-icon,
|
||||
.menu-item .save-config-icon,
|
||||
.menu-item .create-config-icon
|
||||
{
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.tool-bar .save-icon {
|
||||
-glyph-size: 16px;
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.tool-bar .preferences-icon {
|
||||
-glyph-size: 16px;
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.tool-bar .exit-icon {
|
||||
-glyph-size: 16px;
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.tool-bar .delete-icon {
|
||||
-glyph-size: 16px;
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.tool-bar .add-icon {
|
||||
-glyph-size: 16px;
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.tool-bar .export-icon {
|
||||
-glyph-size: 16px;
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.segmented-button-bar .button {
|
||||
-fx-background-color:
|
||||
-darkest-black,
|
||||
-dark-highlight,
|
||||
linear-gradient(to bottom, -light-black 2%, -dark-black 98%);
|
||||
-fx-background-insets: 0, 1 1 1 0, 2 1 1 1;
|
||||
-fx-background-radius: 0;
|
||||
-fx-padding: 0.4em 1.833333em 0.4em 1.833333em;
|
||||
}
|
||||
|
||||
.segmented-button-bar .button.first {
|
||||
-fx-background-insets: 0, 1, 2 1 1 1;
|
||||
-fx-background-radius: 3 0 0 3, 2 0 0 2, 2 0 0 2;
|
||||
}
|
||||
|
||||
.segmented-button-bar .button.last {
|
||||
-fx-background-insets: 0, 1 1 1 0, 2 1 1 1;
|
||||
-fx-background-radius: 0 3 3 0, 0 2 2 0, 0 2 2 0;
|
||||
}
|
||||
|
||||
.segmented-button-bar .button:pressed {
|
||||
-fx-background-color:
|
||||
-darkest-black,
|
||||
rgb(55, 57, 58),
|
||||
linear-gradient(to top, -light-black 2%, -dark-black 98%);
|
||||
}
|
||||
.tool-bar .spacer {
|
||||
-fx-padding: 0 5.417em 0 0;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
-fx-background-radius: 2 2 2 2;
|
||||
-fx-background-color: linear-gradient(#eeeeee, #aaaaaa);
|
||||
-fx-text-fill: black;
|
||||
-fx-font-size: 12px;
|
||||
-fx-padding: 10 10 10 10;
|
||||
}
|
||||
|
||||
.keyword {
|
||||
-fx-fill: purple;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
.semicolon {
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
.paren {
|
||||
-fx-fill: firebrick;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
.bracket {
|
||||
-fx-fill: darkgreen;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
.brace {
|
||||
-fx-fill: teal;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
.string {
|
||||
-fx-fill: blue;
|
||||
}
|
||||
|
||||
.comment {
|
||||
-fx-fill: cadetblue;
|
||||
}
|
||||
|
||||
.paragraph-box:has-caret {
|
||||
-fx-background-color: #f2f9fc;
|
||||
}
|
||||
@@ -1,101 +1,267 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import de.jensd.fx.glyphs.fontawesome.*?>
|
||||
<?import de.jensd.fx.glyphs.*?>
|
||||
<?import de.jensd.fx.glyphs.materialdesignicons.*?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import java.net.URL?>
|
||||
<BorderPane fx:id="applicationPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
|
||||
minWidth="-Infinity" prefHeight="700.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/8.0.66"
|
||||
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>
|
||||
<VBox prefWidth="100.0" BorderPane.alignment="CENTER">
|
||||
<VBox id="background" prefWidth="100.0" BorderPane.alignment="CENTER">
|
||||
<children>
|
||||
<MenuBar>
|
||||
<MenuBar useSystemMenuBar="true">
|
||||
<menus>
|
||||
<Menu mnemonicParsing="false" text="%menu.file">
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="save-icon"/>
|
||||
</graphic>
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" onAction="#openCsv" text="%menu.open.csv">
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="open-icon"/>
|
||||
<MaterialDesignIconView styleClass="open-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
<MenuItem mnemonicParsing="false" onAction="#openConfig" text="%menu.open.config">
|
||||
<MenuItem fx:id="saveMenuItem" disable="true" mnemonicParsing="false" onAction="#saveCsv" text="%menu.save">
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="config-icon"/>
|
||||
<MaterialDesignIconView styleClass="save-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
<MenuItem fx:id="saveAsMenuItem" disable="true" mnemonicParsing="false" onAction="#saveAsCsv" text="%menu.save.as">
|
||||
<graphic>
|
||||
<MaterialDesignIconView styleClass="save-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem fx:id="saveMenuItem" mnemonicParsing="false" onAction="#saveCsv" text="%menu.save" disable="true">
|
||||
<MenuItem fx:id="createConfigMenuItem" disable="true" mnemonicParsing="false" onAction="#createConfig" text="%menu.create.config">
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="save-icon"/>
|
||||
<GlyphsStack>
|
||||
<children>
|
||||
<MaterialDesignIconView styleClass="config-icon" />
|
||||
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="create-config-icon" />
|
||||
</children>
|
||||
</GlyphsStack>
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
<MenuItem fx:id="saveAsMenuItem" mnemonicParsing="false" onAction="#saveAsCsv" text="%menu.save.as" disable="true">
|
||||
<MenuItem fx:id="loadConfigMenuItem" disable="true" mnemonicParsing="false" onAction="#openConfig" text="%menu.open.config">
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="save-icon"/>
|
||||
<GlyphsStack>
|
||||
<children>
|
||||
<MaterialDesignIconView styleClass="config-icon" />
|
||||
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="load-config-icon" />
|
||||
</children>
|
||||
</GlyphsStack>
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
<MenuItem fx:id="saveConfigMenuItem" disable="true" mnemonicParsing="false" onAction="#saveConfig" text="%menu.save.config">
|
||||
<graphic>
|
||||
<GlyphsStack>
|
||||
<children>
|
||||
<MaterialDesignIconView styleClass="config-icon" />
|
||||
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="save-config-icon" />
|
||||
</children>
|
||||
</GlyphsStack>
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
<MenuItem fx:id="saveAsConfigMenuItem" disable="true" mnemonicParsing="false" onAction="#saveAsConfig" text="%menu.save.as.config">
|
||||
<graphic>
|
||||
<GlyphsStack>
|
||||
<children>
|
||||
<MaterialDesignIconView styleClass="config-icon" />
|
||||
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="save-config-icon" />
|
||||
</children>
|
||||
</GlyphsStack>
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#preferences" text="%menu.preferences">
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="preferences-icon"/>
|
||||
<MaterialDesignIconView styleClass="preferences-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
<MenuItem fx:id="exportMenuItem" disable="true" mnemonicParsing="false" onAction="#export" text="%menu.export">
|
||||
<graphic>
|
||||
<MaterialDesignIconView styleClass="export-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#close" text="%menu.close">
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="exit-icon"/>
|
||||
<MaterialDesignIconView styleClass="exit-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="%menu.edit">
|
||||
<items>
|
||||
<MenuItem fx:id="deleteRowMenuItem" disable="true" mnemonicParsing="false" onAction="#deleteRow" text="%menu.delete.row">
|
||||
<graphic>
|
||||
<MaterialDesignIconView styleClass="delete-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
<MenuItem fx:id="addRowMenuItem" disable="true" mnemonicParsing="false" onAction="#addRow" text="%menu.add.row">
|
||||
<graphic>
|
||||
<MaterialDesignIconView styleClass="add-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem fx:id="gotoLineMenuItem" disable="true" mnemonicParsing="false" onAction="#gotoLine" text="%menu.goto.line">
|
||||
<graphic>
|
||||
<MaterialDesignIconView styleClass="goto-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="%menu.help">
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="info-icon"/>
|
||||
</graphic>
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" onAction="#about" text="%menu.about">
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="info-icon"/>
|
||||
<MaterialDesignIconView styleClass="info-icon" />
|
||||
</graphic>
|
||||
</MenuItem>
|
||||
</items>
|
||||
</Menu>
|
||||
</menus>
|
||||
</MenuBar>
|
||||
<ToolBar prefHeight="40.0" prefWidth="200.0">
|
||||
<HBox styleClass="segmented-button-bar">
|
||||
<Button mnemonicParsing="false" onAction="#openCsv" styleClass="first">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.open.csv" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<MaterialDesignIconView styleClass="open-icon" />
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button fx:id="saveButton" disable="true" mnemonicParsing="false" onAction="#saveCsv">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.save" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<MaterialDesignIconView styleClass="save-icon" />
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button fx:id="saveAsButton" disable="true" mnemonicParsing="false" onAction="#saveAsCsv" styleClass="last" text="...">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.save.as" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<MaterialDesignIconView styleClass="save-icon" />
|
||||
</graphic>
|
||||
</Button>
|
||||
</HBox>
|
||||
<Region styleClass="spacer" />
|
||||
<HBox styleClass="segmented-button-bar">
|
||||
<Button fx:id="createConfigButton" disable="true" mnemonicParsing="false" onAction="#createConfig">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.create.config" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<GlyphsStack>
|
||||
<children>
|
||||
<MaterialDesignIconView styleClass="config-icon" />
|
||||
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="create-config-icon" />
|
||||
</children>
|
||||
</GlyphsStack>
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button fx:id="loadConfigButton" disable="true" mnemonicParsing="false" onAction="#openConfig">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.open.config" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<GlyphsStack>
|
||||
<children>
|
||||
<MaterialDesignIconView styleClass="config-icon" />
|
||||
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="load-config-icon" />
|
||||
</children>
|
||||
</GlyphsStack>
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button fx:id="saveConfigButton" disable="true" mnemonicParsing="false" onAction="#saveConfig">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.save.config" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<GlyphsStack>
|
||||
<children>
|
||||
<MaterialDesignIconView styleClass="config-icon" />
|
||||
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="save-config-icon" />
|
||||
</children>
|
||||
</GlyphsStack>
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button fx:id="saveAsConfigButton" disable="true" mnemonicParsing="false" onAction="#saveAsConfig" styleClass="last" text="...">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.save.as.config" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<GlyphsStack>
|
||||
<children>
|
||||
<MaterialDesignIconView styleClass="config-icon" />
|
||||
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="save-config-icon" />
|
||||
</children>
|
||||
</GlyphsStack>
|
||||
|
||||
</graphic>
|
||||
</Button>
|
||||
</HBox>
|
||||
<Region styleClass="spacer" />
|
||||
<HBox styleClass="segmented-button-bar">
|
||||
<Button fx:id="deleteRowButton" disable="true" mnemonicParsing="false" onAction="#deleteRow" styleClass="first">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.delete.row" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<MaterialDesignIconView styleClass="delete-icon" />
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button fx:id="addRowButton" disable="true" mnemonicParsing="false" onAction="#addRow" styleClass="last">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.add.row" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<MaterialDesignIconView styleClass="add-icon" />
|
||||
</graphic>
|
||||
</Button>
|
||||
</HBox>
|
||||
<Region styleClass="spacer" />
|
||||
<HBox styleClass="segmented-button-bar">
|
||||
<Button mnemonicParsing="false" onAction="#preferences" styleClass="first">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.preferences" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<MaterialDesignIconView styleClass="preferences-icon" />
|
||||
</graphic>
|
||||
</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">
|
||||
<tooltip>
|
||||
<Tooltip text="%menu.close" />
|
||||
</tooltip>
|
||||
<graphic>
|
||||
<MaterialDesignIconView styleClass="exit-icon" />
|
||||
</graphic>
|
||||
</Button>
|
||||
</HBox>
|
||||
</ToolBar>
|
||||
</children>
|
||||
</VBox>
|
||||
</top>
|
||||
<center>
|
||||
<SplitPane dividerPositions="0.8" prefHeight="160.0" prefWidth="200.0" BorderPane.alignment="CENTER">
|
||||
<items>
|
||||
<AnchorPane fx:id="tableWrapper">
|
||||
<TableView fx:id="tableView" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0"
|
||||
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"
|
||||
BorderPane.alignment="CENTER">
|
||||
<TableView fx:id="tableView" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" BorderPane.alignment="CENTER">
|
||||
<columns>
|
||||
</columns>
|
||||
</TableView>
|
||||
</AnchorPane>
|
||||
<VBox>
|
||||
<children>
|
||||
<Label text="%title.validation.errors">
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0"/>
|
||||
</padding>
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="error-title-icon"/>
|
||||
</graphic>
|
||||
</Label>
|
||||
<ListView fx:id="errorList" minWidth="10.0" prefWidth="200.0" VBox.vgrow="ALWAYS"/>
|
||||
</children>
|
||||
</VBox>
|
||||
</items>
|
||||
</SplitPane>
|
||||
</center>
|
||||
<left>
|
||||
</left>
|
||||
@@ -109,26 +275,27 @@
|
||||
<ColumnConstraints hgrow="NEVER" minWidth="10.0" />
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="NEVER" minWidth="10.0" />
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0"/>
|
||||
<ColumnConstraints hgrow="NEVER" minWidth="10.0" />
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" />
|
||||
<ColumnConstraints hgrow="NEVER" minWidth="10.0" />
|
||||
<ColumnConstraints fillWidth="false" halignment="RIGHT" hgrow="NEVER" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<FontAwesomeIconView styleClass="open-icon" GridPane.hgrow="NEVER"/>
|
||||
<MaterialDesignIconView styleClass="file-document-icon" GridPane.hgrow="NEVER" />
|
||||
<Label text="%stateline.csv" GridPane.columnIndex="1" GridPane.hgrow="NEVER" />
|
||||
<Label fx:id="csvName" GridPane.columnIndex="2" GridPane.hgrow="ALWAYS" />
|
||||
<Label text="%stateline.state" GridPane.columnIndex="3" GridPane.hgrow="NEVER"/>
|
||||
<Label fx:id="stateName" GridPane.columnIndex="4" GridPane.hgrow="ALWAYS"/>
|
||||
<FontAwesomeIconView styleClass="open-icon" GridPane.columnIndex="5" GridPane.hgrow="NEVER"/>
|
||||
<Label text="%stateline.configuration" GridPane.columnIndex="6" GridPane.hgrow="NEVER"/>
|
||||
<Label fx:id="configurationName" GridPane.columnIndex="7" GridPane.hgrow="ALWAYS"/>
|
||||
<MaterialDesignIconView styleClass="config-check-icon" GridPane.columnIndex="3" GridPane.hgrow="NEVER" />
|
||||
<Label text="%stateline.configuration" GridPane.columnIndex="4" GridPane.hgrow="NEVER" />
|
||||
<Label fx:id="configurationName" GridPane.columnIndex="5" GridPane.hgrow="ALWAYS" />
|
||||
<Label text="%lineNumber" GridPane.columnIndex="7" />
|
||||
<Label fx:id="currentLineNumber" text="" GridPane.columnIndex="8" />
|
||||
</children>
|
||||
<BorderPane.margin>
|
||||
<Insets top="4.0" left="8.0" bottom="4.0" right="8.0"/>
|
||||
<Insets bottom="4.0" left="8.0" right="8.0" top="4.0" />
|
||||
</BorderPane.margin>
|
||||
</GridPane>
|
||||
</bottom>
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
menu.open.csv = Open CSV File
|
||||
menu.open.config = Open Validation Config
|
||||
menu.create.config = Create Validation Config
|
||||
menu.save = Save
|
||||
menu.save.as = Save As ...
|
||||
menu.save.config = Save Validation Config
|
||||
menu.save.as.config = Save Validation Config as ...
|
||||
menu.close = Close
|
||||
menu.about = About
|
||||
menu.file = File
|
||||
menu.edit = Edit
|
||||
menu.help = Help
|
||||
menu.preferences = Preferences
|
||||
menu.delete.row = Delete row
|
||||
menu.add.row = Add row
|
||||
menu.goto.line = Goto line
|
||||
menu.export = Export error log
|
||||
|
||||
title.validation.errors = Validation Errors:
|
||||
|
||||
stateline.csv = CSV:
|
||||
@@ -24,6 +32,10 @@ dialog.exit.text = There are changes made to the csv file. If you close now, the
|
||||
dialog.preferences.title = Preferences
|
||||
dialog.preferences.header.text = Preferences
|
||||
|
||||
dialog.goto.line.title = Go to line
|
||||
dialog.goto.line.header.text = Go to given line (max. {0}) and select line!
|
||||
dialog.goto.line.label = Line:
|
||||
|
||||
preferences.quoteChar = Quote character:
|
||||
preferences.delimiterChar = Delimiter character:
|
||||
preferences.ignoreEmptyLines = Ignore empty lines:
|
||||
@@ -34,6 +46,7 @@ preferences.quoteMode = Quote mode:
|
||||
validation.message.not.empty = should not be empty
|
||||
validation.message.integer = should be an integer
|
||||
validation.message.double = should be a double
|
||||
validation.message.email = should be an email address
|
||||
validation.message.alphanumeric = should be alphanumeric
|
||||
validation.message.groovy.exception = groovy script '{0}' throws exception: {1}
|
||||
validation.message.groovy.return.null = groovy script '{0}' returns null
|
||||
@@ -41,7 +54,46 @@ 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.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.uri = should be an uri
|
||||
validation.message.uuid = should be an uuid
|
||||
validation.message.binary = should be a base64 encoded string representing binary data
|
||||
|
||||
validation.message.header.length = number of headers is not correct! there are {0} but there should be {1}
|
||||
validation.message.header.match = header number {0} does not match "{1}" should be "{3}"
|
||||
validation.message.header.match = header number {0} does not match "{1}" should be "{2}"
|
||||
validation.message.value.of = Value {0} is not part of this list {1}
|
||||
|
||||
validation.rule.label.not_empty = not empty
|
||||
validation.rule.label.integer = integer
|
||||
validation.rule.label.double = double
|
||||
validation.rule.label.minlength = minimum length:
|
||||
validation.rule.label.maxlength = maximum length:
|
||||
validation.rule.label.dateformat = date format:
|
||||
validation.rule.label.alphanumeric = alphanumeric
|
||||
validation.rule.label.regexp = regular expression:
|
||||
validation.rule.label.value_of = value in list:
|
||||
validation.rule.label.groovy = groovy:
|
||||
validation.rules.active = active
|
||||
validation.rules.name = rule
|
||||
validation.rules.value = value
|
||||
validation.rule.label.unique = Unique in column
|
||||
validation.rule.format = Format:
|
||||
validation.rule.type = Type:
|
||||
|
||||
dialog.validation.rules.title = Validation rules
|
||||
dialog.validation.rules.header = Validation rules of column "{0}"
|
||||
context.menu.edit.column.rules = Edit rules
|
||||
|
||||
lineNumber = Selected line:
|
||||
|
||||
log.header.message = {0} has {1} errors
|
||||
log.message = row {0} column {1} : {2}
|
||||
|
||||
column = column
|
||||
|
||||
format.type.DEFAULT = default
|
||||
format.type.EMAIL = email
|
||||
format.type.URI = uri
|
||||
format.type.BINARY = binary
|
||||
format.type.UUID = uuid
|
||||
|
||||
@@ -8,14 +8,23 @@
|
||||
|
||||
menu.open.csv = CSV Datei \u00f6ffnen
|
||||
menu.open.config = Pr\u00fcfkonfiguration \u00f6ffnen
|
||||
menu.create.config = Pr\u00fcfkonfiguration erzeugen
|
||||
menu.save = Speichern
|
||||
menu.save.as = Speichern als ...
|
||||
menu.save.config = Pr\u00fcfkonfiguration speichern
|
||||
menu.save.as.config = Pr\u00fcfkonfiguration speichern als ...
|
||||
|
||||
menu.close = Beenden
|
||||
menu.about = \u00dcber ...
|
||||
menu.file = Datei
|
||||
menu.edit = Bearbeiten
|
||||
menu.help = Hilfe
|
||||
menu.preferences = Einstellungen
|
||||
menu.delete.row = Zeile l\u00f6schen
|
||||
menu.add.row = Zeile hinzuf\u00fcgen
|
||||
menu.goto.line = Springe zur Zeile
|
||||
menu.export = Export Fehlerdatei
|
||||
|
||||
title.validation.errors = Fehler in der Datei:
|
||||
|
||||
stateline.csv = CSV:
|
||||
@@ -28,6 +37,10 @@ state.unchanged = Unver\u00e4ndert
|
||||
dialog.preferences.title = Eigenschaften
|
||||
dialog.preferences.header.text = Eigenschaften
|
||||
|
||||
dialog.goto.line.title = Springe zur Zeile
|
||||
dialog.goto.line.header.text = Zur angegebenen Zeile (max. {0}) springen und ausw\u00e4hlen!
|
||||
dialog.goto.line.label = Zeile:
|
||||
|
||||
dialog.exit.title = Anwendung beenden
|
||||
dialog.exit.header.text = M\u00f6chten Sie wirklich die Anwendung beenden?
|
||||
dialog.exit.text = Es gibt noch ungespeicherte \u00c4nderungen, die verloren gehen, wenn Sie die Anwendung jetzt beenden.
|
||||
@@ -42,6 +55,7 @@ preferences.quoteMode = Einfassungsmodus:
|
||||
validation.message.not.empty = Darf nicht leer sein.
|
||||
validation.message.integer = Muss eine Zahl sein.
|
||||
validation.message.double = Muss eine Gleitkommazahl sein
|
||||
validation.message.email = Muss eine Email-Adresse sein
|
||||
validation.message.alphanumeric = Darf nur Zahlen und Buchstaben enthalten.
|
||||
validation.message.groovy.exception = groovy script '{0}' wirft folgenden Fehler: {1}
|
||||
validation.message.groovy.return.null = groovy script '{0}' meldet "null"
|
||||
@@ -49,7 +63,47 @@ 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.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.uri = Muss eine URI sein
|
||||
validation.message.uuid = Muss eine UUID sein
|
||||
validation.message.binary = Muss ein base64 encoded Text sein, der bin\u00e4re Daten enth\u00e4lt
|
||||
|
||||
validation.message.header.length = Anzahl der \u00dcberschriften ist nicht korrekt! Es sind {0} aber es sollten {1} sein
|
||||
validation.message.header.match = \u00dcberschrift in Spalte {0} stimmt nicht. "{1}" sollte "{3}" sein
|
||||
validation.message.value.of = Der Wert {0} ist nicht in der Liste {1} enthalten
|
||||
|
||||
validation.rule.label.not_empty = Nicht leer
|
||||
validation.rule.label.integer = Zahl
|
||||
validation.rule.label.double = Gleitkommazahl
|
||||
validation.rule.label.minlength = Minimale L\u00e4nge:
|
||||
validation.rule.label.maxlength = Maximale L\u00e4nge:
|
||||
validation.rule.label.dateformat = Datumsformat:
|
||||
validation.rule.label.alphanumeric = Nur Zahlen und Buchstaben:
|
||||
validation.rule.label.regexp = Regul\u00e4rer Ausdruck:
|
||||
validation.rule.label.value_of = In der Liste:
|
||||
validation.rule.label.groovy = groovy:
|
||||
validation.rules.active = Aktiv
|
||||
validation.rules.name = Regel
|
||||
validation.rules.value = Wert
|
||||
validation.rule.label.unique = Einmalig in Spalte
|
||||
validation.rule.format = Format:
|
||||
validation.rule.type = Typ:
|
||||
|
||||
dialog.validation.rules.title = Pr\u00fcfregeln
|
||||
dialog.validation.rules.header = Pr\u00fcfregeln f\u00fcr die Spalte "{0}"
|
||||
|
||||
context.menu.edit.column.rules = Pr\u00fcfregeln bearbeiten
|
||||
|
||||
lineNumber = Ausgew\u00e4hlte Zeile:
|
||||
|
||||
log.header.message = {0} hat {1} Fehler
|
||||
log.message = Zeile {0} Spalte {1} : {2}
|
||||
|
||||
column = Spalte
|
||||
|
||||
format.type.DEFAULT = Standard
|
||||
format.type.EMAIL = Email
|
||||
format.type.URI = URI
|
||||
format.type.BINARY = Bin\u00e4r
|
||||
format.type.UUID = UUID
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import java.net.URL?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
<?import javafx.scene.control.ComboBox?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.Separator?>
|
||||
<?import javafx.scene.control.Spinner?>
|
||||
<?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?>
|
||||
|
||||
<GridPane hgap="20.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="800.0" vgap="6.0" xmlns="http://javafx.com/javafx/8.0.76-ea" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints halignment="LEFT" hgrow="NEVER" />
|
||||
<ColumnConstraints halignment="LEFT" hgrow="ALWAYS" />
|
||||
<ColumnConstraints halignment="LEFT" hgrow="NEVER" />
|
||||
<ColumnConstraints halignment="LEFT" hgrow="ALWAYS" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" valignment="TOP" vgrow="ALWAYS" />
|
||||
<RowConstraints />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<Label text="%validation.rule.type" GridPane.columnSpan="2" GridPane.halignment="LEFT" GridPane.hgrow="ALWAYS" />
|
||||
<Label text="%validation.rule.format" GridPane.columnSpan="2" GridPane.halignment="LEFT" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" />
|
||||
<ComboBox fx:id="typeComboBox" maxWidth="1.7976931348623157E308" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.halignment="LEFT" GridPane.hgrow="ALWAYS" />
|
||||
<ComboBox fx:id="formatComboBox" prefWidth="150.0" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="1" visible="false" />
|
||||
<TextField fx:id="formatTextField" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="1" visible="false" />
|
||||
<CheckBox fx:id="enableNotEmptyRule" mnemonicParsing="false" text="%validation.rule.label.not_empty" GridPane.rowIndex="3" />
|
||||
<CheckBox fx:id="enableUniqueRule" mnemonicParsing="false" text="%validation.rule.label.unique" GridPane.columnIndex="2" GridPane.rowIndex="3" />
|
||||
<CheckBox fx:id="enableMinLengthRule" mnemonicParsing="false" text="%validation.rule.label.minlength" GridPane.rowIndex="4" />
|
||||
<Spinner fx:id="minLengthSpinner" GridPane.columnIndex="1" GridPane.rowIndex="4" />
|
||||
<CheckBox fx:id="enableMaxLengthRule" mnemonicParsing="false" text="%validation.rule.label.maxlength" GridPane.columnIndex="2" GridPane.rowIndex="4" />
|
||||
<Spinner fx:id="maxLengthSpinner" GridPane.columnIndex="3" GridPane.rowIndex="4" />
|
||||
<CheckBox fx:id="enableRegexpRule" mnemonicParsing="false" text="%validation.rule.label.regexp" GridPane.rowIndex="5" />
|
||||
<TextField fx:id="regexpRuleTextField" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="5" />
|
||||
<CheckBox fx:id="enableValueOfRule" mnemonicParsing="false" text="%validation.rule.label.value_of" GridPane.rowIndex="6" />
|
||||
<TextField fx:id="valueOfRuleTextField" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="6" />
|
||||
<CheckBox fx:id="enableGroovyRule" mnemonicParsing="false" text="%validation.rule.label.groovy" GridPane.rowIndex="7">
|
||||
<GridPane.margin>
|
||||
<Insets top="8.0" />
|
||||
</GridPane.margin>
|
||||
</CheckBox>
|
||||
<CodeArea fx:id="groovyRuleTextArea" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="7">
|
||||
<GridPane.margin>
|
||||
<Insets top="8.0" />
|
||||
</GridPane.margin>
|
||||
</CodeArea>
|
||||
<Separator prefWidth="200.0" GridPane.columnSpan="4" GridPane.rowIndex="2" />
|
||||
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
|
||||
</padding>
|
||||
<stylesheets>
|
||||
<URL value="@/ninja/javafx/smartcsv/fx/smartcsv.css" />
|
||||
</stylesheets>
|
||||
</GridPane>
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -26,12 +26,10 @@
|
||||
|
||||
package ninja.javafx.smartcsv.fx.table.model;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.Validator;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* unit test for the csv model
|
||||
@@ -77,20 +75,6 @@ public class CSVModelTest {
|
||||
assertThat(sut.getRows().indexOf(newRow), is(newRow.getRowNumber()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void set_validator_calls_when_model_has_data() {
|
||||
|
||||
// setup
|
||||
Validator validator = mock(Validator.class);
|
||||
setup_model_with_one_row_one_column_and_value();
|
||||
|
||||
// execution
|
||||
sut.setValidator(validator);
|
||||
|
||||
// assertion
|
||||
verify(validator).isValid(TESTHEADER, TESTVALUE, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// private methods
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package ninja.javafx.smartcsv.fx.table.model;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.Validator;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.hasKey;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* unit test for row class
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class ConfigMock {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constants
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private static final String HEADER_SECTION_KEY = "headers";
|
||||
private static final String COLUMN_SECTION_KEY = "columns";
|
||||
private static final String LIST_KEY = "list";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// mocks
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
public static Config headerSectionConfig(String[] headerNames) {
|
||||
|
||||
Config headerSectionConfig = mock(Config.class);
|
||||
Config listConfig = mock(Config.class);
|
||||
|
||||
when(headerSectionConfig.hasPath(HEADER_SECTION_KEY)).thenReturn(true);
|
||||
when(headerSectionConfig.getConfig(HEADER_SECTION_KEY)).thenReturn(listConfig);
|
||||
|
||||
when(listConfig.hasPath(LIST_KEY)).thenReturn(true);
|
||||
when(listConfig.getStringList(LIST_KEY)).thenReturn(asList(headerNames));
|
||||
|
||||
return headerSectionConfig;
|
||||
}
|
||||
|
||||
|
||||
public static Config columnSectionConfig(String column, String validation, Object value) {
|
||||
|
||||
Config columnSectionConfig = mock(Config.class);
|
||||
Config columnConfig = mock(Config.class);
|
||||
Config validatorConfig = mock(Config.class);
|
||||
|
||||
when(columnSectionConfig.hasPath(COLUMN_SECTION_KEY)).thenReturn(true);
|
||||
when(columnSectionConfig.getConfig(COLUMN_SECTION_KEY)).thenReturn(columnConfig);
|
||||
|
||||
when(columnConfig.hasPath(column)).thenReturn(true);
|
||||
when(columnConfig.getConfig(column)).thenReturn(validatorConfig);
|
||||
|
||||
when(validatorConfig.hasPath(validation)).thenReturn(true);
|
||||
if (value instanceof Boolean) {
|
||||
when(validatorConfig.getBoolean(validation)).thenReturn((Boolean) value);
|
||||
} else if (value instanceof String) {
|
||||
when(validatorConfig.getString(validation)).thenReturn((String) value);
|
||||
} else if (value instanceof Integer) {
|
||||
when(validatorConfig.getInt(validation)).thenReturn((Integer) value);
|
||||
} else if (value instanceof List) {
|
||||
when(validatorConfig.getStringList(validation)).thenReturn((List<String>) value);
|
||||
}
|
||||
|
||||
return columnSectionConfig;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
Copyright (c) 2015-2016 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
|
||||
@@ -26,20 +26,20 @@
|
||||
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import ninja.javafx.smartcsv.validation.configuration.ValidationConfiguration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static ninja.javafx.smartcsv.validation.ConfigMock.headerSectionConfig;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -52,7 +52,7 @@ public class HeaderValidationTest {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parameters
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private Config config;
|
||||
private ValidationConfiguration config;
|
||||
private Boolean expectedResult;
|
||||
private List<ValidationMessage> expectedErrors;
|
||||
private String[] headerNames;
|
||||
@@ -66,11 +66,12 @@ public class HeaderValidationTest {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parameterized constructor
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
public HeaderValidationTest(String[] configHeaderNames,
|
||||
public HeaderValidationTest(String configHeaderNames,
|
||||
String[] headerNames,
|
||||
Boolean expectedResult,
|
||||
List<ValidationMessage> expectedErrors) {
|
||||
this.config = headerSectionConfig(configHeaderNames);
|
||||
Gson gson = new GsonBuilder().create();
|
||||
this.config = gson.fromJson(configHeaderNames, ValidationConfiguration.class);
|
||||
this.headerNames = headerNames;
|
||||
this.expectedResult = expectedResult;
|
||||
this.expectedErrors = expectedErrors;
|
||||
@@ -81,7 +82,7 @@ public class HeaderValidationTest {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@Before
|
||||
public void initialize() {
|
||||
sut = new Validator(config);
|
||||
sut = new Validator(config, new TestColumnValueProvider());
|
||||
}
|
||||
|
||||
|
||||
@@ -106,11 +107,30 @@ public class HeaderValidationTest {
|
||||
@Parameterized.Parameters
|
||||
public static Collection validationConfigurations() {
|
||||
return asList(new Object[][] {
|
||||
{ new String[] {}, new String[] {}, true, null },
|
||||
{ new String[] {"a"}, new String[] {"a"}, true, null },
|
||||
{ new String[] {"a"}, new String[] {"b"}, false, singletonList(new ValidationMessage("validation.message.header.match", "0", "a", "b"))},
|
||||
{ new String[] {"a"}, new String[] {"a","b"}, false, singletonList(new ValidationMessage("validation.message.header.length", "2", "1"))},
|
||||
{ new String[] {"a", "b"}, new String[] {"b", "a"}, false, asList(new ValidationMessage("validation.message.header.match", "0", "a", "b"), new ValidationMessage("validation.message.header.match", "1", "b", "a")) }
|
||||
{ json(), new String[] {}, true, null },
|
||||
{ json("a"), new String[] {"a"}, true, null },
|
||||
{ json("a"), new String[] {"b"}, false, singletonList(new ValidationMessage("validation.message.header.match", "0", "a", "b"))},
|
||||
{ json("a"), new String[] {"a","b"}, false, singletonList(new ValidationMessage("validation.message.header.length", "2", "1"))},
|
||||
{ json("a", "b"), new String[] {"b", "a"}, false, asList(new ValidationMessage("validation.message.header.match", "0", "a", "b"), new ValidationMessage("validation.message.header.match", "1", "b", "a")) }
|
||||
});
|
||||
}
|
||||
|
||||
public static String json(String... headerNames) {
|
||||
|
||||
String json = "{ \"fields\": [";
|
||||
|
||||
for (String headerName: headerNames) {
|
||||
json += "{\"name\" : \""+headerName+"\" },";
|
||||
}
|
||||
|
||||
if (headerNames != null && headerNames.length > 0) {
|
||||
json = json.substring(0, json.length() - 1);
|
||||
}
|
||||
|
||||
json += "]}";
|
||||
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import ninja.javafx.smartcsv.fx.table.model.ColumnValueProvider;
|
||||
|
||||
/**
|
||||
* @author abi
|
||||
*/
|
||||
public class TestColumnValueProvider implements ColumnValueProvider {
|
||||
@Override
|
||||
public String getValue(int row, String column) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfRows() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import ninja.javafx.smartcsv.validation.configuration.ValidationConfiguration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static ninja.javafx.smartcsv.validation.ConfigMock.columnSectionConfig;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
@@ -23,8 +26,7 @@ public class ValidatorTest {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parameters
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private Config config;
|
||||
private String column;
|
||||
private String config;
|
||||
private String value;
|
||||
private Boolean expectedResult;
|
||||
private ValidationMessage expectedError;
|
||||
@@ -39,15 +41,11 @@ public class ValidatorTest {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parameterized constructor
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
public ValidatorTest(String configcolumn,
|
||||
String configValidation,
|
||||
Object configValue,
|
||||
String column,
|
||||
public ValidatorTest(String config,
|
||||
String value,
|
||||
Boolean expectedResult,
|
||||
ValidationMessage expectedError) {
|
||||
this.config = columnSectionConfig(configcolumn, configValidation, configValue);
|
||||
this.column = column;
|
||||
this.config = config;
|
||||
this.value = value;
|
||||
this.expectedResult = expectedResult;
|
||||
this.expectedError = expectedError;
|
||||
@@ -59,7 +57,9 @@ public class ValidatorTest {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@Before
|
||||
public void initialize() {
|
||||
sut = new Validator(config);
|
||||
Gson gson = new GsonBuilder().create();
|
||||
ValidationConfiguration validationConfiguration = gson.fromJson(config, ValidationConfiguration.class);
|
||||
sut = new Validator(validationConfiguration, new TestColumnValueProvider());
|
||||
}
|
||||
|
||||
|
||||
@@ -68,8 +68,14 @@ public class ValidatorTest {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@Test
|
||||
public void validation() {
|
||||
System.out.println("===================================================");
|
||||
System.out.println(config);
|
||||
System.out.println(value + " " + expectedResult + " " + expectedError);
|
||||
System.out.println("===================================================\n");
|
||||
|
||||
|
||||
// execution
|
||||
ValidationError result = sut.isValid(column, value, 0);
|
||||
ValidationError result = sut.isValid(0, "column", value);
|
||||
|
||||
// assertion
|
||||
assertThat(result == null, is(expectedResult));
|
||||
@@ -84,30 +90,80 @@ public class ValidatorTest {
|
||||
@Parameterized.Parameters
|
||||
public static Collection validationConfigurations() {
|
||||
return asList(new Object[][] {
|
||||
{ "column", "not empty", true, "column", "value", true, null },
|
||||
{ "column", "not empty", true, "column", "", false, new ValidationMessage("validation.message.not.empty") },
|
||||
{ "column", "not empty", true, "column", null, false, new ValidationMessage("validation.message.not.empty") },
|
||||
{ "column", "integer", true, "column", "999", true, null },
|
||||
{ "column", "integer", true, "column", "a", false, new ValidationMessage("validation.message.integer") },
|
||||
{ "column", "double", true, "column", "999", true, null },
|
||||
{ "column", "double", true, "column", "999.000", true, null },
|
||||
{ "column", "double", true, "column", "a", false, new ValidationMessage("validation.message.double") },
|
||||
{ "column", "minlength", 2, "column", "12", true, null },
|
||||
{ "column", "minlength", 2, "column", "1", false, new ValidationMessage("validation.message.min.length", "2") },
|
||||
{ "column", "maxlength", 2, "column", "12", true, null },
|
||||
{ "column", "maxlength", 2, "column", "123", false, new ValidationMessage("validation.message.max.length", "2") },
|
||||
{ "column", "date", "yyyyMMdd", "column", "20151127", true, null },
|
||||
{ "column", "date", "yyyyMMdd", "column", "27.11.2015", false, new ValidationMessage("validation.message.date.format", "yyyyMMdd") },
|
||||
{ "column", "alphanumeric", true, "column", "abcABC123", true, null },
|
||||
{ "column", "alphanumeric", true, "column", "-abcABC123", false, new ValidationMessage("validation.message.alphanumeric") },
|
||||
{ "column", "regexp", "[a-z]*", "column", "abc", true, null },
|
||||
{ "column", "regexp", "[a-z]*", "column", "abcA", false, new ValidationMessage("validation.message.regexp", "[a-z]*") },
|
||||
{ "column", "groovy", "value.contains('a')? 'true' : 'no a inside'", "column", "abcdef", true, null },
|
||||
{ "column", "groovy", "value.contains('a')? 'true' : 'no a inside'", "column", "bcdefg", false, new ValidationMessage("no a inside") },
|
||||
{ "column", "value of", asList("a","b","c","d","e"), "column", "c", true, null },
|
||||
{ "column", "value of", asList("a","b","c","d","e"), "column", "f", false, new ValidationMessage("validation.message.value.of", "f", "a, b, c, d, e") },
|
||||
{ constraintsJSON("string", "required", true), "value", true, null },
|
||||
{ constraintsJSON("string", "required", true), "", false, new ValidationMessage("validation.message.not.empty") },
|
||||
{ constraintsJSON("string", "required", true), null, false, new ValidationMessage("validation.message.not.empty") },
|
||||
{ constraintsJSON("integer", null, true), "999", true, null },
|
||||
{ constraintsJSON("integer", null, true), "a", false, new ValidationMessage("validation.message.integer") },
|
||||
{ constraintsJSON("number", null, true), "999", true, null },
|
||||
{ constraintsJSON("number", null, true), "999.000", true, null },
|
||||
{ constraintsJSON("number", null, true), "a", false, new ValidationMessage("validation.message.double") },
|
||||
{ constraintsJSON("string", "minLength", 2), "12", true, null },
|
||||
{ constraintsJSON("string", "minLength", 2), "1", false, new ValidationMessage("validation.message.min.length", "2") },
|
||||
{ constraintsJSON("string", "maxLength", 2), "12", true, null },
|
||||
{ constraintsJSON("string", "maxLength", 2), "123", false, new ValidationMessage("validation.message.max.length", "2") },
|
||||
{ constraintsJSON("string", "pattern", "[a-z]*"), "abc", true, null },
|
||||
{ constraintsJSON("string", "pattern", "[a-z]*"), "abcA", false, new ValidationMessage("validation.message.regexp", "[a-z]*") },
|
||||
{ constraintsJSON("string", "enum", asList("a","b","c","d","e")), "c", true, null },
|
||||
{ constraintsJSON("string", "enum", asList("a","b","c","d","e")), "f", false, new ValidationMessage("validation.message.value.of", "f", "a, b, c, d, e") },
|
||||
|
||||
{ formatJSON("string", null), "some string", true, null },
|
||||
{ formatJSON("string", "email"), "test@javafx.ninja", true, null },
|
||||
{ formatJSON("string", "email"), "wrong email", false, new ValidationMessage("validation.message.email") },
|
||||
{ formatJSON("string", "uri"), "http://www.javafx.ninja", true, null },
|
||||
{ formatJSON("string", "uri"), "!$%&/()", false, new ValidationMessage("validation.message.uri") },
|
||||
{ formatJSON("string", "binary"), "dGVzdA==", true, null },
|
||||
{ formatJSON("string", "binary"), "no binary", false, new ValidationMessage("validation.message.binary") },
|
||||
{ formatJSON("string", "uuid"), "6ba7b810-9dad-11d1-80b4-00c04fd430c8", true, null },
|
||||
{ formatJSON("string", "uuid"), "no uuid", false, new ValidationMessage("validation.message.uuid") },
|
||||
{ formatJSON("date", null), "2015-11-27", true, null },
|
||||
{ formatJSON("date", null), "27.11.2015", false, new ValidationMessage("validation.message.date.format", "yyyy-MM-dd") },
|
||||
{ formatJSON("date", "yyyyMMdd"), "20151127", true, null },
|
||||
{ formatJSON("date", "yyyyMMdd"), "27.11.2015", false, new ValidationMessage("validation.message.date.format", "yyyyMMdd") },
|
||||
|
||||
|
||||
{ customAttributeJSON( "groovy", "value.contains('a')? 'true' : 'no a inside'"), "abcdef", true, null },
|
||||
{ customAttributeJSON( "groovy", "value.contains('a')? 'true' : 'no a inside'"), "bcdefg", false, new ValidationMessage("no a inside") },
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public static String constraintsJSON(String type, String constraint, Object value) {
|
||||
String json = "{\"fields\": [ { \"name\": \"column\", \"type\" : \"" + type +"\"";
|
||||
|
||||
if (constraint != null) {
|
||||
json += ", \"constraints\": { \"" + constraint + "\":";
|
||||
if (value instanceof String) {
|
||||
json += "\"" + value + "\"";
|
||||
} else if (value instanceof List) {
|
||||
List<String> list = (List<String>) value;
|
||||
json += "[" + list.stream().collect(joining(", ")) + "]";
|
||||
} else {
|
||||
json += value;
|
||||
}
|
||||
json += "}";
|
||||
}
|
||||
json += "}]}";
|
||||
return json;
|
||||
}
|
||||
|
||||
public static String formatJSON(String type, String format) {
|
||||
String json = "{\"fields\": [ { \"name\": \"column\", \"type\" : \"" + type +"\"";
|
||||
|
||||
if (format != null) {
|
||||
json += ", \"format\": \"" + format + "\"";
|
||||
}
|
||||
json += "}]}";
|
||||
return json;
|
||||
}
|
||||
|
||||
public static String customAttributeJSON(String attribute, String value) {
|
||||
String json = "{\"fields\": [ { \"name\": \"column\", \"type\" : \"string\"";
|
||||
|
||||
if (attribute != null) {
|
||||
json += ", \""+attribute+"\": \"" + value + "\"";
|
||||
}
|
||||
json += "}]}";
|
||||
return json;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user