49 Commits

Author SHA1 Message Date
Andreas Billmann 6b424a4ce6 version 0.3 2016-01-12 22:56:36 +01:00
Andreas Billmann 21b139cc6c usability of preferences dialog 2016-01-12 22:42:24 +01:00
Andreas Billmann 79ba44615a fixed test 2016-01-12 22:41:52 +01:00
Andreas Billmann 7bb2d78c4b i18n preferences dialog 2016-01-12 22:03:20 +01:00
Andreas Billmann 134d7fedc8 enable save menu items only when csv file is loaded 2016-01-12 21:58:27 +01:00
Andreas Billmann 469895b27e extracted load and save service and generalize file writer 2016-01-12 21:52:08 +01:00
Andreas Billmann 72a8674cfc unused file removed 2016-01-11 11:15:11 +01:00
Andreas Billmann c87267a0df saving preferences to file 2016-01-11 11:14:25 +01:00
Andreas Billmann 6348c018df refactored load preferences method 2016-01-11 09:16:40 +01:00
Andreas Billmann 789c5012a4 read and edit csv preferences 2016-01-11 09:03:22 +01:00
Andreas Billmann 5762354d19 update fontawesome to version 8.8 2016-01-09 21:21:34 +01:00
Andreas Billmann 701cba7581 main content of about dialog changed to fxml to support hyperlinks and better layout 2015-12-30 14:22:52 +01:00
Andreas Billmann dd458b1b70 static import 2015-12-30 09:52:00 +01:00
Andreas Billmann 0b6d6edda6 explicit exit as implicit exit is disabled 2015-12-30 09:51:43 +01:00
Andreas Billmann af5c64426c added fontawesomefx to have icons in the project 2015-12-29 22:43:01 +01:00
Andreas Billmann 9a0960bdbc always quote values 2015-12-18 12:24:48 +01:00
Andreas Billmann c87471f0d1 show state and allow exit based on state 2015-12-18 12:19:19 +01:00
Andreas Billmann 67f92cd60f fixed some class comments 2015-12-18 09:00:03 +01:00
Andreas Billmann e3eb684ad9 screenshot of video 2015-12-18 02:13:59 +01:00
Andreas Billmann 47d4307aa2 screenshot of video 2015-12-18 02:13:21 +01:00
Andreas Billmann 8d0073f1bc empty strings shouldn't be validated by complex validations 2015-12-18 01:53:29 +01:00
Andreas Billmann 9b8b0080ff refresh list after correcting a value 2015-12-18 01:47:38 +01:00
Andreas Billmann 941f1b9037 as it is useable i changed the version to 0.2 2015-12-18 01:20:20 +01:00
Andreas Billmann 73e3e6c171 as it is useable i changed the version to 0.2 2015-12-18 01:16:37 +01:00
Andreas Billmann 5f335debdc as it is useable i changed the version to 0.2 2015-12-18 01:10:21 +01:00
Andreas Billmann e8caf5e0a5 start with a maximized application 2015-12-18 01:05:36 +01:00
Andreas Billmann f90d2fbe33 remember the last directory and fixed NPE 2015-12-18 01:00:58 +01:00
Andreas Billmann ee94a5904e improve the design of the validation error list 2015-12-18 01:00:18 +01:00
Andreas Billmann a5435c6b5f support double value validation 2015-12-17 23:55:08 +01:00
Andreas Billmann a67937a262 support list of possible values 2015-12-17 23:41:20 +01:00
Andreas Billmann fc8627ff18 added css to the fxml to support future css settings 2015-12-17 23:02:08 +01:00
Andreas Billmann 2b16775db6 scroll to the line before the selected error is, this helps recognizing the correct line 2015-12-17 22:57:26 +01:00
Andreas Billmann b3e1ad6fb8 Merge remote-tracking branch 'remotes/origin/feature/header_validation' 2015-12-17 22:09:57 +01:00
Andreas Billmann 09834ab07f i18n parameterized validation error messages 2015-12-17 22:09:32 +01:00
Andreas Billmann c9d13d4d58 little fluent API to shorten boild plate code 2015-12-17 21:32:52 +01:00
Andreas Billmann 5121b998c5 prepare the usage of dynamic validation messages 2015-12-17 21:15:37 +01:00
Andreas Billmann a67f793670 fixed broken test 2015-12-17 21:14:45 +01:00
Andreas Billmann 8ebc18e452 replaced static validation error text 2015-12-17 20:52:09 +01:00
Andreas Billmann 9278bfa13a add support for i18n validation messages 2015-12-17 20:44:07 +01:00
Andreas Billmann 5d53fff577 optimize imports 2015-12-17 19:56:14 +01:00
Andreas Billmann f80c91c06a start i18n 2015-12-17 19:55:40 +01:00
Andreas Billmann 11fb9b1094 new feature: clickable error list 2015-12-07 22:41:59 +01:00
Andreas Billmann 873a880971 fixed NPE when validation is not available on revalidate call 2015-12-07 20:21:35 +01:00
Andreas Billmann feabaa70a9 first steps for header validation 2015-12-04 16:22:21 +01:00
Andreas Billmann 1d5441af4d about dialog 2015-12-02 13:53:20 +01:00
Andreas Billmann 1efcc42dcd removed testfx 2015-12-02 13:34:45 +01:00
Andreas Billmann 6b4d957cfd git ignore file 2015-12-02 13:20:09 +01:00
frosch95 f27d6b76e2 Create README.md 2015-11-28 23:15:23 +01:00
Andreas Billmann 07084bd18e Initial commit 2015-11-28 23:06:14 +01:00
58 changed files with 4048 additions and 652 deletions
+76
View File
@@ -0,0 +1,76 @@
# Created by .ignore support plugin (hsz.mobi)
### Java template
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Gradle template
.gradle
build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
*.iml
## Directory-based project format:
.idea/
# if you remove the above rule, at least ignore the following:
# User-specific stuff:
# .idea/workspace.xml
# .idea/tasks.xml
# .idea/dictionaries
# Sensitive or high-churn files:
# .idea/dataSources.ids
# .idea/dataSources.xml
# .idea/sqlDataSources.xml
# .idea/dynamic.xml
# .idea/uiDesigner.xml
# Gradle:
# .idea/gradle.xml
# .idea/libraries
# Mongo Explorer plugin:
# .idea/mongoSettings.xml
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
+40
View File
@@ -0,0 +1,40 @@
# 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.
##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
[![short video about the application](http://img.youtube.com/vi/SH0UAtPG6Eg/0.jpg)](https://youtu.be/SH0UAtPG6Eg)
##License
###The MIT License (MIT)
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.
+27
View File
@@ -0,0 +1,27 @@
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'
repositories {
mavenCentral()
jcenter()
}
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: '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'
}
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
#Thu Oct 01 19:02:27 CEST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip
Vendored
+164
View File
@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=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.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
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=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
Vendored
+90
View File
@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@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 Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz 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.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
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
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

-109
View File
@@ -1,109 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="description" content="SmartCSV.fx : 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.">
<link rel="stylesheet" type="text/css" media="screen" href="stylesheets/stylesheet.css">
<title>SmartCSV.fx</title>
</head>
<body>
<!-- HEADER -->
<div id="header_wrap" class="outer">
<header class="inner">
<a id="forkme_banner" href="https://github.com/frosch95/SmartCSV.fx">View on GitHub</a>
<h1 id="project_title">SmartCSV.fx</h1>
<h2 id="project_tagline">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.</h2>
<section id="downloads">
<a class="zip_download_link" href="https://github.com/frosch95/SmartCSV.fx/zipball/master">Download this project as a .zip file</a>
<a class="tar_download_link" href="https://github.com/frosch95/SmartCSV.fx/tarball/master">Download this project as a tar.gz file</a>
</section>
</header>
</div>
<!-- MAIN CONTENT -->
<div id="main_content_wrap" class="outer">
<section id="main_content" class="inner">
<h1>
<a id="smartcsvfx" class="anchor" href="#smartcsvfx" aria-hidden="true"><span class="octicon octicon-link"></span></a>SmartCSV.fx</h1>
<h2>
<a id="description" class="anchor" href="#description" aria-hidden="true"><span class="octicon octicon-link"></span></a>Description</h2>
<p>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.</p>
<h2>
<a id="motivation" class="anchor" href="#motivation" aria-hidden="true"><span class="octicon octicon-link"></span></a>Motivation</h2>
<p>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.</p>
<h2>
<a id="video" class="anchor" href="#video" aria-hidden="true"><span class="octicon octicon-link"></span></a>Video</h2>
<p><a href="https://youtu.be/eUh_WLx1OwI"><img src="http://img.youtube.com/vi/eUh_WLx1OwI/0.jpg" alt="short video about the application"></a></p>
<h2>
<a id="wiki" class="anchor" href="#wiki" aria-hidden="true"><span class="octicon octicon-link"></span></a>Documentation</h2>
<p><a href="https://github.com/frosch95/SmartCSV.fx/wiki">goto the GitHub Wiki</a> for the documentation</p>
<p><a href="https://github.com/frosch95/SmartCSV.fx/wiki/What's-New%3F">What's New?</a> release information</p>
<h2>
<a id="binary" class="anchor" href="#binary" aria-hidden="true"><span class="octicon octicon-link"></span></a>Binary</h2>
<p>binary distribution of <a href="https://github.com/frosch95/SmartCSV.fx/releases">SmartCSV.fx</a></p>
<p>unzip the file and double click the SmartCSV.fx.bat (windows) or enter ./SmartCSV.fx (linux) to start the application</p>
<h2>Talks</h2>
<p><a href="http://javafx.ninja/talks/introduction/">Introduction</a></p>
<h2>
<a id="license" class="anchor" href="#license" aria-hidden="true"><span class="octicon octicon-link"></span></a>License</h2>
<h3>
<a id="the-mit-license-mit" class="anchor" href="#the-mit-license-mit" aria-hidden="true"><span class="octicon octicon-link"></span></a>The MIT License (MIT)</h3>
<p>Copyright (c) 2015-2019 Andreas Billmann <a href="mailto:andreas.billmann@javafx.ninja">andreas.billmann@javafx.ninja</a></p>
<p>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:</p>
<p>The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.</p>
<p>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.</p>
</section>
</div>
<!-- FOOTER -->
<div id="footer_wrap" class="outer">
<footer class="inner">
<p class="copyright">SmartCSV.fx maintained by <a href="https://github.com/frosch95">frosch95</a></p>
<p>Published with <a href="https://pages.github.com">GitHub Pages</a></p>
</footer>
</div>
</body>
</html>
-1
View File
@@ -1 +0,0 @@
console.log('This would be the main JS file.');
+28
View File
@@ -0,0 +1,28 @@
The MIT License (MIT)
------------------------------------------------------------------------------------------------------------------------
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.
-1
View File
@@ -1 +0,0 @@
{"name":"SmartCSV.fx","tagline":"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.","body":"# SmartCSV.fx\r\n##Description\r\nA 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.\r\n\r\n##Motivation\r\nAt 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, \r\neven in a \"normal\" CSV editor. So I decided to write this simple JavaFX application.\r\n\r\n##Video\r\n[![short video about the application](http://img.youtube.com/vi/SH0UAtPG6Eg/0.jpg)](https://youtu.be/SH0UAtPG6Eg)\r\n\r\n##License\r\n###The MIT License (MIT)\r\n\r\n\r\nCopyright (c) 2015 Andreas Billmann <andreas.billmann@javafx.ninja>\r\n\r\n\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\n\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\n\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE.\r\n","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."}
+2
View File
@@ -0,0 +1,2 @@
rootProject.name = 'SmartCSV.ninja.javafx.smartcsv.fx'
@@ -0,0 +1,37 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv;
import java.io.File;
import java.io.IOException;
/**
* read some file
*/
public interface FileReader {
void read(File filename) throws IOException;
}
@@ -0,0 +1,37 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv;
import java.io.File;
import java.io.IOException;
/**
* write some file
*/
public interface FileWriter {
void write(File filename) throws IOException;
}
@@ -0,0 +1,45 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.csv;
import org.supercsv.prefs.CsvPreference;
/**
*
*/
public class CSVConfigurable {
protected CsvPreference csvPreference;
public CSVConfigurable() {
csvPreference = CsvPreference.EXCEL_NORTH_EUROPE_PREFERENCE;
}
public void setCsvPreference(CsvPreference csvPreference) {
this.csvPreference = csvPreference;
}
}
@@ -0,0 +1,79 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.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;
import java.io.File;
import java.io.IOException;
import java.util.Map;
/**
* reads the csv file and stores the values in csv model
*/
@Service
public class CSVFileReader extends CSVConfigurable implements FileReader {
private CSVModel model;
@Override
public void read(File file) throws IOException {
ICsvMapReader mapReader = null;
try {
mapReader = new CsvMapReader(new java.io.FileReader(file.getAbsoluteFile()), csvPreference);
model = new CSVModel();
// the header columns are used as the keys to the Map
String[] header = mapReader.getHeader(true);
model.setHeader(header);
Map<String, String> customerMap;
while ((customerMap = mapReader.read(header)) != null) {
CSVRow row = model.addRow();
for (String column : header) {
row.addValue(column, customerMap.get(column));
}
}
} finally {
if (mapReader != null) {
mapReader.close();
}
}
}
public CSVModel getData() {
return model;
}
}
@@ -0,0 +1,87 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.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;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
import static java.util.stream.Collectors.toMap;
/**
* filewriter for the csv
*/
@Service
public class CSVFileWriter extends CSVConfigurable implements ninja.javafx.smartcsv.FileWriter {
private CSVModel model;
public void setModel(CSVModel model) {
this.model = model;
}
@Override
public void write(File filename) throws IOException {
ICsvMapWriter mapWriter = null;
try {
mapWriter = new CsvMapWriter(new FileWriter(filename.getAbsolutePath()), csvPreference);
mapWriter.writeHeader(model.getHeader());
for(CSVRow row: model.getRows()) {
Map<String, String> columns = convertMapFromModel(row);
mapWriter.write(columns, model.getHeader());
}
}
finally {
if( mapWriter != null ) {
mapWriter.close();
}
}
}
/**
* transforms the column map from CSVValue to a simple Map<String,String>
* @param row the row to convert
* @return a simple map for the supercvs writer
*/
private Map<String, String> convertMapFromModel(CSVRow row) {
return row.getColumns().entrySet().stream()
.collect(
toMap(
Map.Entry::getKey,
e -> e.getValue().getValue().getValue() != null ? e.getValue().getValue().getValue() : ""
)
);
}
}
@@ -0,0 +1,72 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import java.io.IOException;
import java.io.InputStream;
import java.util.ResourceBundle;
public abstract class FXMLController implements InitializingBean, Initializable {
protected Node view;
protected String fxmlFilePath;
protected String resourcePath;
public abstract void setFxmlFilePath(String filePath);
@Value("${resource.main}")
public void setResourceBundle(String resourcePath) {
this.resourcePath = resourcePath;
}
@Override
public void afterPropertiesSet() throws Exception {
loadFXML();
}
protected final void loadFXML() throws IOException {
try (InputStream fxmlStream = getClass().getResourceAsStream(fxmlFilePath)) {
FXMLLoader loader = new FXMLLoader();
loader.setResources(ResourceBundle.getBundle(this.resourcePath));
loader.setController(this);
this.view = (loader.load(fxmlStream));
} catch (Throwable t) {
t.printStackTrace();
}
}
public Node getView() {
return view;
}
}
@@ -0,0 +1,104 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx;
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;
import static javafx.application.Platform.exit;
@Configuration
@ComponentScan("ninja.javafx")
@PropertySource(value = "classpath:/ninja/javafx/smartcsv/fx/application.properties")
public class SmartCSV extends Application {
private AnnotationConfigApplicationContext appContext;
@Override
public void start(Stage primaryStage) throws Exception {
appContext = new AnnotationConfigApplicationContext(SmartCSV.class);
String name = appContext.getEnvironment().getProperty("application.name");
String version = appContext.getEnvironment().getProperty("application.version");
Platform.setImplicitExit(false);
AboutController aboutController = appContext.getBean(AboutController.class);
aboutController.setHostServices(getHostServices());
try {
showUI(primaryStage, name, version);
} catch (Exception e) {
e.printStackTrace();
}
}
@Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Override
public void stop() throws Exception {
if (appContext != null) {
appContext.close();
}
super.stop();
}
public static void main(String[] args) {
launch(args);
}
private void showUI(Stage primaryStage, String name, String version) {
SmartCSVController smartCVSController = appContext.getBean(SmartCSVController.class);
Scene scene = new Scene((Parent) smartCVSController.getView());
primaryStage.setScene(scene);
primaryStage.setTitle(String.format("%s %s", name, version));
primaryStage.show();
primaryStage.setMaximized(true);
primaryStage.setOnCloseRequest(event -> {
if (!smartCVSController.canExit()) {
event.consume();
} else {
exit();
}
});
}
}
@@ -0,0 +1,491 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Node;
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.fx.about.AboutController;
import ninja.javafx.smartcsv.fx.list.ValidationErrorListCell;
import ninja.javafx.smartcsv.fx.preferences.PreferencesController;
import ninja.javafx.smartcsv.fx.table.ObservableMapValueFactory;
import ninja.javafx.smartcsv.fx.table.ValidationCellFactory;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
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.preferences.PreferencesFileReader;
import ninja.javafx.smartcsv.preferences.PreferencesFileWriter;
import ninja.javafx.smartcsv.validation.ValidationError;
import ninja.javafx.smartcsv.validation.ValidationFileReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.supercsv.prefs.CsvPreference;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Optional;
import java.util.ResourceBundle;
import static java.lang.Math.max;
import static javafx.application.Platform.exit;
import static javafx.application.Platform.runLater;
import static javafx.scene.layout.AnchorPane.*;
/**
* main controller of the application
*/
@Component
public class SmartCSVController extends FXMLController {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constants
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private static final File PREFERENCES_FILE = new File(System.getProperty("user.home") +
File.separator +
".SmartCSV.fx" +
File.separator + "" +
"preferences.json");
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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 LoadFileService loadFileService;
@Autowired
private SaveFileService saveFileService;;
@FXML
private BorderPane applicationPane;
@FXML
private Label csvName;
@FXML
private Label configurationName;
@FXML
private Label stateName;
@FXML
private ListView errorList;
@FXML
private AnchorPane tableWrapper;
@FXML
private MenuItem saveMenuItem;
@FXML
private MenuItem saveAsMenuItem;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// members
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private ValidationCellFactory cellFactory;
private CSVModel model;
private TableView<CSVRow> tableView;
private BooleanProperty fileChanged = new SimpleBooleanProperty(true);
private ResourceBundle resourceBundle;
private File currentCsvFile;
private File currentConfigFile;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// init
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@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();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// setter
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Value("${fxml.smartcvs.view}")
@Override
public void setFxmlFilePath(String filePath) {
this.fxmlFilePath = filePath;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// actions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@FXML
public void openCsv(ActionEvent actionEvent) {
currentCsvFile = loadFile(csvLoader,
"CSV files (*.csv)",
"*.csv",
"Open CSV",
currentCsvFile);
enableSaveMenuItems();
setCsvFileName();
}
@FXML
public void openConfig(ActionEvent actionEvent) {
currentConfigFile = loadFile(validationLoader,
"JSON files (*.json)",
"*.json",
"Open Validation Configuration",
currentConfigFile);
setConfigFileName();
}
@FXML
public void saveCsv(ActionEvent actionEvent) {
csvFileWriter.setModel(model);
useSaveFileService(csvFileWriter, currentCsvFile);
}
@FXML
public void saveAsCsv(ActionEvent actionEvent) {
csvFileWriter.setModel(model);
currentCsvFile = saveFile(csvFileWriter,
"CSV files (*.csv)",
"*.csv",
currentCsvFile);
setCsvFileName();
}
@FXML
public void close(ActionEvent actionEvent) {
if (canExit()) {
exit();
}
}
@FXML
public void about(ActionEvent actionEvent) {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("About");
alert.setHeaderText("SmartCSV.fx");
alert.getDialogPane().setContent(aboutController.getView());
alert.showAndWait();
}
@FXML
public void preferences(ActionEvent actionEvent) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setGraphic(null);
alert.setTitle(resourceBundle.getString("dialog.preferences.title"));
alert.setHeaderText(resourceBundle.getString("dialog.preferences.header.text"));
alert.getDialogPane().setContent(preferencesController.getView());
Node okButton = alert.getDialogPane().lookupButton(ButtonType.OK);
okButton.disableProperty().bind(preferencesController.validProperty().not());
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK){
CsvPreference csvPreference = preferencesController.getCsvPreference();
setCsvPreference(csvPreference);
saveCsvPreferences(csvPreference);
} else {
preferencesController.setCsvPreference(preferencesLoader.getCSVpreference());
}
}
public boolean canExit() {
boolean canExit = true;
if (model != null && fileChanged.get()) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle(resourceBundle.getString("dialog.exit.title"));
alert.setHeaderText(resourceBundle.getString("dialog.exit.header.text"));
alert.setContentText(resourceBundle.getString("dialog.exit.text"));
Optional<ButtonType> result = alert.showAndWait();
if (result.get() != ButtonType.OK){
canExit = false;
}
}
return canExit;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void enableSaveMenuItems() {
if (currentCsvFile != null) {
saveMenuItem.setDisable(false);
saveAsMenuItem.setDisable(false);
}
}
private void setCsvFileName() {
if (currentCsvFile != null) {
csvName.setText(currentCsvFile.getName());
} else {
csvName.setText("");
}
}
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);
} catch (IOException e) {
e.printStackTrace();
}
}
private void createPreferenceFile() throws IOException {
if (!PREFERENCES_FILE.exists()) {
createPreferencesFileFolder();
PREFERENCES_FILE.createNewFile();
}
}
private void createPreferencesFileFolder() {
if (!PREFERENCES_FILE.getParentFile().exists()) {
PREFERENCES_FILE.getParentFile().mkdir();
}
}
private void setCsvPreference(CsvPreference csvPreference) {
csvLoader.setCsvPreference(csvPreference);
csvFileWriter.setCsvPreference(csvPreference);
preferencesController.setCsvPreference(csvPreference);
}
private File loadFile(FileReader fileReader,
String filterText,
String filter,
String title,
File initChildFile) {
final FileChooser fileChooser = new FileChooser();
//Set extension filter
final FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(filterText, filter);
fileChooser.getExtensionFilters().add(extFilter);
fileChooser.setTitle(title);
if (initChildFile != null) {
fileChooser.setInitialDirectory(initChildFile.getParentFile());
}
//Show open file dialog
File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow());
if (file != null) {
useLoadFileService(fileReader, file);
return file;
} else {
return initChildFile;
}
}
private File saveFile(FileWriter writer, String filterText, String filter, File initFile) {
File file = initFile;
if (model != 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());
}
fileChooser.setTitle("Save File");
//Show open file dialog
file = fileChooser.showSaveDialog(applicationPane.getScene().getWindow());
if (file != null) {
useSaveFileService(writer, file);
}
}
return file;
}
private void useLoadFileService(FileReader fileReader, File file) {
loadFileService.setFile(file);
loadFileService.setFileReader(fileReader);
loadFileService.restart();
loadFileService.setOnSucceeded(event -> runLater(() -> {
resetContent();
fileChanged.setValue(false);
}));
}
private void useSaveFileService(FileWriter writer, File file) {
saveFileService.setFile(file);
saveFileService.setWriter(writer);
saveFileService.restart();
saveFileService.setOnSucceeded(event -> runLater(() -> {
resetContent();
fileChanged.setValue(false);
}));
}
/**
* 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<>();
for (String column : model.getHeader()) {
addColumn(column, tableView);
}
tableView.getItems().setAll(model.getRows());
tableView.setEditable(true);
setBottomAnchor(tableView, 0.0);
setTopAnchor(tableView, 0.0);
setLeftAnchor(tableView, 0.0);
setRightAnchor(tableView, 0.0);
tableWrapper.getChildren().setAll(tableView);
errorList.setItems(model.getValidationError());
}
}
/**
* 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) {
TableColumn column = new TableColumn(header);
column.setCellValueFactory(new ObservableMapValueFactory(header));
column.setCellFactory(cellFactory);
column.setEditable(true);
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();
});
}
});
tableView.getColumns().add(column);
}
private void scrollToError() {
ValidationError entry = (ValidationError)errorList.getSelectionModel().getSelectedItem();
if (entry != null) {
if (entry.getLineNumber() != null) {
tableView.scrollTo(max(0, entry.getLineNumber() - 1));
tableView.getSelectionModel().select(entry.getLineNumber());
} else {
tableView.scrollTo(0);
}
}
}
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("");
}
}
}
@@ -0,0 +1,68 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.about;
import javafx.application.HostServices;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Hyperlink;
import ninja.javafx.smartcsv.fx.FXMLController;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.net.URL;
import java.util.ResourceBundle;
/**
* The about controller
*/
@Component
public class AboutController extends FXMLController {
private HostServices hostServices;
@Value("${fxml.smartcvs.about.view}")
@Override
public void setFxmlFilePath(String filePath) {
this.fxmlFilePath = filePath;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
}
@FXML
public void openLinkInBrowser(ActionEvent actionEvent) {
Hyperlink hyperlink = (Hyperlink)actionEvent.getSource();
hostServices.showDocument(hyperlink.getText());
}
public void setHostServices(HostServices hostServices) {
this.hostServices = hostServices;
}
}
@@ -0,0 +1,70 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.list;
import javafx.scene.control.ListCell;
import javafx.scene.text.Text;
import ninja.javafx.smartcsv.validation.ValidationError;
import java.util.ResourceBundle;
import static ninja.javafx.smartcsv.fx.util.I18nValidationUtil.getI18nValidatioMessage;
/**
* Cell to show the error text
*/
public class ValidationErrorListCell extends ListCell<ValidationError> {
private ResourceBundle resourceBundle;
public ValidationErrorListCell(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);
setGraphic(null);
}
private void addContent(ValidationError validationError) {
setText(null);
Text text = new Text(getI18nValidatioMessage(resourceBundle, validationError));
text.setWrappingWidth(180);
setGraphic(text);
}
}
@@ -0,0 +1,135 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.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;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import ninja.javafx.smartcsv.fx.FXMLController;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.supercsv.prefs.CsvPreference;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.function.UnaryOperator;
import static ninja.javafx.smartcsv.preferences.QuoteModeHelper.getQuoteMode;
import static ninja.javafx.smartcsv.preferences.QuoteModeHelper.getQuoteModeName;
/**
* controller for preferences
*/
@Component
public class PreferencesController extends FXMLController {
@FXML
private TextField quoteChar;
@FXML
private TextField delimiterChar;
@FXML
private CheckBox surroundingSpacesNeedQuotes;
@FXML
private CheckBox ignoreEmptyLines;
@FXML
private ComboBox<String> quoteMode;
private String endOfLineSymbols;
private BooleanProperty valid = new SimpleBooleanProperty(true);
@Value("${fxml.smartcvs.preferences.view}")
@Override
public void setFxmlFilePath(String filePath) {
this.fxmlFilePath = filePath;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
quoteMode.getItems().addAll("normal", "always", "column");
UnaryOperator<TextFormatter.Change> allowOnlyOneCharacter = change -> {
if (change.isContentChange()) {
if (change.getControlNewText().length() > 1) {
return null;
}
}
return change;
};
quoteChar.setTextFormatter(new TextFormatter(allowOnlyOneCharacter));
quoteChar.textProperty().addListener(observable -> {revalidate();});
delimiterChar.setTextFormatter(new TextFormatter(allowOnlyOneCharacter));
delimiterChar.textProperty().addListener(observable -> {revalidate();});
}
private void revalidate() {
valid.setValue(quoteChar.getText().length() == 1 && delimiterChar.getText().length() == 1);
}
public void setCsvPreference(CsvPreference csvPreference) {
quoteChar.setText(Character.toString(csvPreference.getQuoteChar()));
delimiterChar.setText(Character.toString((char)csvPreference.getDelimiterChar()));
surroundingSpacesNeedQuotes.setSelected(csvPreference.isSurroundingSpacesNeedQuotes());
ignoreEmptyLines.setSelected(csvPreference.isIgnoreEmptyLines());
quoteMode.getSelectionModel().select(getQuoteModeName(csvPreference.getQuoteMode()));
endOfLineSymbols = csvPreference.getEndOfLineSymbols();
}
public CsvPreference getCsvPreference() {
return new CsvPreference.Builder(quoteChar.getText().charAt(0), delimiterChar.getText().charAt(0), endOfLineSymbols)
.useQuoteMode(getQuoteMode(quoteMode.getSelectionModel().getSelectedItem()))
.surroundingSpacesNeedQuotes(surroundingSpacesNeedQuotes.isSelected())
.ignoreEmptyLines(ignoreEmptyLines.isSelected())
.build();
}
public boolean getValid() {
return valid.get();
}
public BooleanProperty validProperty() {
return valid;
}
public void setValid(boolean valid) {
this.valid.set(valid);
}
}
@@ -0,0 +1,145 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.table;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCode;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
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.I18nValidationUtil.getI18nValidatioMessage;
/**
* cell representation which indicates if a cell is valid and not
* and allows editing
*/
public class EditableValidationCell extends TableCell<CSVRow, CSVValue> {
private ValueTextField textField;
private ResourceBundle resourceBundle;
public EditableValidationCell(ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
}
@Override
public void startEdit() {
super.startEdit();
setTextField();
runLater(() -> {
textField.requestFocus();
textField.selectAll();
});
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText(getItem().getValue());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
@Override
protected void updateItem(CSVValue item, boolean empty) {
super.updateItem(item, empty);
if (item == null || item.getValidationError() == null || isEditing()) {
setStyle("");
setTooltip(null);
} else if (item.getValidationError() != null) {
setStyle("-fx-background-color: #ff8888");
setTooltip(new Tooltip(getI18nValidatioMessage(resourceBundle, item.getValidationError())));
}
if (item == null || empty) {
setTextInCell(null);
} else {
if (isEditing()) {
setTextField();
textField.setValue(item);
} else {
setTextInCell(item.getValue());
}
}
}
private void setTextField() {
if (textField == null) {
createTextField();
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
private void setTextInCell(String text) {
setGraphic(null);
setText(text);
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
private void createTextField() {
textField = new ValueTextField(getItem());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.setOnKeyPressed(t -> {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(textField.getValue());
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
});
textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue && textField != null) {
commitEdit(textField.getValue());
}
});
}
private class ValueTextField extends TextField {
private CSVValue value;
public ValueTextField(CSVValue value) {
setValue(value);
}
public void setValue(CSVValue value) {
this.value = value;
setText(value.getValue());
}
public CSVValue getValue() {
value.setValue(getText());
return value;
}
}
}
@@ -0,0 +1,53 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.table;
import javafx.beans.property.ObjectProperty;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
/**
* cell value factory for the columns in the tableview
*/
public class ObservableMapValueFactory implements
Callback<TableColumn.CellDataFeatures<CSVRow, CSVValue>, ObjectProperty<CSVValue>> {
private final Object key;
public ObservableMapValueFactory(Object key) {
this.key = key;
}
@Override
public ObjectProperty<CSVValue> call(TableColumn.CellDataFeatures<CSVRow, CSVValue> features) {
CSVRow row = features.getValue();
ObjectProperty<CSVValue> value = row.getColumns().get(key);
return value;
}
}
@@ -0,0 +1,52 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.table;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
import java.util.ResourceBundle;
/**
* cell factory for rendering a value in the cell
*/
public class ValidationCellFactory implements Callback<TableColumn<CSVRow, CSVValue>, TableCell<CSVRow, CSVValue>> {
private ResourceBundle resourceBundle;
public ValidationCellFactory(ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
}
@Override
public TableCell<CSVRow, CSVValue> call(TableColumn<CSVRow, CSVValue> param) {
return new EditableValidationCell(resourceBundle);
}
}
@@ -0,0 +1,133 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.table.model;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import ninja.javafx.smartcsv.validation.ValidationError;
import ninja.javafx.smartcsv.validation.Validator;
/**
* 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 {
private Validator validator;
private ObservableList<CSVRow> rows = FXCollections.observableArrayList();
private String[] header;
private ObservableList<ValidationError> validationError = FXCollections.observableArrayList();
/**
* sets the validator for the data revalidates
* @param validator the validator for this data
*/
public void setValidator(Validator validator) {
this.validator = validator;
revalidate();
}
/**
* returns the data as a list of rows of the
* @return list of rows
*/
public ObservableList<CSVRow> getRows() {
return rows;
}
public ObservableList<ValidationError> getValidationError() {
return validationError;
}
/**
* 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;
}
/**
* sets the column headers as string array
* @param header the headers of the columns
*/
public void setHeader(String[] header) {
this.header = header;
revalidate();
}
/**
* returns the column headers
* @return the column headers
*/
public String[] getHeader() {
return header;
}
/**
* walks through the data and validates each value
*/
public void revalidate() {
validationError.clear();
if (header != null && validator != null) {
addValidationError(validator.isHeaderValid(header));
}
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 void addValidationError(ValidationError validationError) {
if (validationError != null) {
this.validationError.add(validationError);
}
}
}
@@ -0,0 +1,90 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.table.model;
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
*/
public void setRowNumber(int rowNumber) {
this.rowNumber = rowNumber;
}
/**
* return the row number
* @return row number
*/
public int getRowNumber() {
return rowNumber;
}
/**
* returns the columns with data as Map
* @return columns with data
*/
public ObservableMap<String, ObjectProperty<CSVValue>> getColumns() {
return columns;
}
/**
* stores the given value in the given column of this row
* @param column column name
* @param value the value to store
*/
public void 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));
}
}
@@ -0,0 +1,112 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.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.
* It also knows about the position (row and column)
* 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
*/
public String getValue() {
return value.get();
}
/**
* JavaFX property representation of the real value
* @return property of real value
*/
public StringProperty valueProperty() {
return value;
}
/**
* sets the real value
* @param value the real value
*/
public void setValue(String value) {
if (validator != null) {
valid = validator.isValid(column, value, rowNumber);
}
this.value.set(value);
}
/**
* returns if the value is valid to the rules of the validator
* @return
*/
public ValidationError getValidationError() {
return valid;
}
/**
* sets the state if a value is valid or not
* @param valid the validation state
*/
protected void setValidationError(ValidationError valid) {
this.valid = valid;
}
}
@@ -0,0 +1,71 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.util;
import ninja.javafx.smartcsv.validation.ValidationError;
import ninja.javafx.smartcsv.validation.ValidationMessage;
import java.io.StringWriter;
import java.util.List;
import java.util.ResourceBundle;
import static java.text.MessageFormat.format;
/**
* This class makes validation messages readable in supported languages
*/
public class I18nValidationUtil {
public static String getI18nValidatioMessage(ResourceBundle resourceBundle, ValidationError error) {
List<ValidationMessage> validationMessages = error.getMessages();
StringWriter message = new StringWriter();
for (ValidationMessage validationMessage: validationMessages) {
if (resourceBundle.containsKey(validationMessage.getKey())) {
String resourceText = resourceBundle.getString(validationMessage.getKey());
if (validationMessage.getParameters().length > 0) {
message.append(format(resourceText, validationMessage.getParameters())).append("\n");
} else {
message.append(resourceText).append("\n");
}
} else {
message.append(validationMessage.getKey()).append("\n");
}
}
if (!validationMessages.isEmpty()) {
return cutOffLastLineBreak(message.toString());
}
return "";
}
private static String cutOffLastLineBreak(String message) {
return message.substring(0, message.length()-1);
}
}
@@ -0,0 +1,63 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.util;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import ninja.javafx.smartcsv.FileReader;
import java.io.File;
/**
* Service class for async load of a csv file
*/
@org.springframework.stereotype.Service
public class LoadFileService extends Service {
private File file;
private FileReader fileReader;
public void setFile(File value) {
file = value;
}
public void setFileReader(FileReader fileReader) {
this.fileReader = fileReader;
}
@Override
protected Task createTask() {
return new Task() {
@Override
protected Void call() throws Exception {
if (file != null) {
fileReader.read(file);
}
return null;
}
};
}
}
@@ -0,0 +1,70 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.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;
/**
* Service class for async load of a csv file
*/
@org.springframework.stereotype.Service
public class SaveFileService extends Service {
private File file;
private FileWriter writer;
public void setWriter(FileWriter writer) {
this.writer = writer;
}
public void setFile(File value) {
file = value;
}
@Override
protected Task createTask() {
return new Task() {
@Override
protected Void call() throws Exception {
try {
writer.write(file);
} catch (Throwable ex) {
ex.printStackTrace();
}
return null;
}
};
}
}
@@ -0,0 +1,81 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.preferences;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
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 static ninja.javafx.smartcsv.preferences.QuoteModeHelper.getQuoteMode;
/**
* file reader for the preferences
*/
@Service
public class PreferencesFileReader implements FileReader {
private Config config;
private CsvPreference csvPreference;
public PreferencesFileReader() {
csvPreference = new CsvPreference.
Builder(CsvPreference.EXCEL_NORTH_EUROPE_PREFERENCE).
useQuoteMode(new AlwaysQuoteMode()).build();
}
@Override
public void read(File filename) throws IOException {
config = ConfigFactory.parseFile(filename);
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");
csvPreference = new CsvPreference.Builder(quoteChar, delimiterChar, endOfLineSymbols)
.useQuoteMode(getQuoteMode(quoteMode))
.surroundingSpacesNeedQuotes(surroundingSpacesNeedQuotes)
.ignoreEmptyLines(ignoreEmptyLines)
.build();
}
}
public CsvPreference getCSVpreference() {
return csvPreference;
}
}
@@ -0,0 +1,67 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.preferences;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigRenderOptions;
import ninja.javafx.smartcsv.FileWriter;
import org.springframework.stereotype.Service;
import org.supercsv.prefs.CsvPreference;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
/**
* Save preferences to configuration file
*/
@Service
public class PreferencesFileWriter implements FileWriter {
private CsvPreference csvPreference;
public void setCsvPreference(CsvPreference csvPreference) {
this.csvPreference = csvPreference;
}
public void write(File file) throws IOException {
Map<String, Object> preferences = new HashMap<>();
preferences.put("quoteChar", Character.toString(csvPreference.getQuoteChar()));
preferences.put("delimiterChar", Character.toString((char)csvPreference.getDelimiterChar()));
preferences.put("endOfLineSymbols", csvPreference.getEndOfLineSymbols());
preferences.put("surroundingSpacesNeedQuotes", csvPreference.isSurroundingSpacesNeedQuotes());
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());
}
}
@@ -0,0 +1,56 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.preferences;
import org.supercsv.quote.AlwaysQuoteMode;
import org.supercsv.quote.ColumnQuoteMode;
import org.supercsv.quote.NormalQuoteMode;
import org.supercsv.quote.QuoteMode;
/**
* Helper class for mapping quote quoteModeName
*/
public class QuoteModeHelper {
public static QuoteMode getQuoteMode(String quoteModeName) {
switch (quoteModeName) {
case "always": return new AlwaysQuoteMode();
case "column": return new ColumnQuoteMode();
default: return new NormalQuoteMode();
}
}
public static String getQuoteModeName(QuoteMode quoteMode) {
if (quoteMode instanceof AlwaysQuoteMode) {
return "always";
} else if (quoteMode instanceof ColumnQuoteMode) {
return "column";
} else {
return "normal";
}
}
}
@@ -0,0 +1,70 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import java.util.ArrayList;
import java.util.List;
/**
* This class holds all the error messages
* for a single cell and the information in
* which row the cell is
*/
public class ValidationError {
private List<ValidationMessage> messages = new ArrayList<>();
private Integer lineNumber;
private ValidationError(Integer lineNumber) {
this.lineNumber = lineNumber;
}
public static ValidationError withLineNumber(int lineNumber) {
return new ValidationError(lineNumber);
}
public static ValidationError withoutLineNumber() {
return new ValidationError(-1);
}
public Integer getLineNumber() {
return lineNumber;
}
public List<ValidationMessage> getMessages() {
return messages;
}
public ValidationError add(String key, String... parameters) {
messages.add(new ValidationMessage(key, parameters));
return this;
}
public boolean isEmpty() {
return messages.isEmpty();
}
}
@@ -0,0 +1,53 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import ninja.javafx.smartcsv.FileReader;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;
/**
* This class loads the constraints as json config
*/
@Service
public class ValidationFileReader implements FileReader {
private Config config;
@Override
public void read(File file) throws IOException {
config = ConfigFactory.parseFile(file);
}
public Validator getValidator() {
return new Validator(config);
}
}
@@ -0,0 +1,79 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import java.util.Arrays;
/**
* Stores the i18n key and possible parameters for validation messages
*/
public class ValidationMessage {
private String key;
private String[] parameters;
public ValidationMessage(String key, String... parameters) {
this.key = key;
this.parameters = parameters;
}
public String getKey() {
return key;
}
public String[] getParameters() {
return parameters;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ValidationMessage that = (ValidationMessage) o;
if (key != null ? !key.equals(that.key) : that.key != null) return false;
// Probably incorrect - comparing Object[] arrays with Arrays.equals
return Arrays.equals(parameters, that.parameters);
}
@Override
public int hashCode() {
int result = key != null ? key.hashCode() : 0;
result = 31 * result + Arrays.hashCode(parameters);
return result;
}
@Override
public String toString() {
return "ValidationMessage{" +
"key='" + key + '\'' +
", parameters=" + Arrays.toString(parameters) +
'}';
}
}
@@ -0,0 +1,289 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import com.typesafe.config.Config;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import org.codehaus.groovy.control.CompilationFailedException;
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.*;
/**
* This class checks all the validations defined in the
* Config against a given value
*/
public class Validator {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// member variables
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private Config validationConfig;
private GroovyShell shell = new GroovyShell();
private Map<String, Script> scriptCache = new HashMap<>();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constructors
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* JSON configuration for this validator
* @param validationConfig
*/
public Validator(Config validationConfig) {
this.validationConfig = validationConfig;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// oublic methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 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) {
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 (!error.isEmpty()) {
result = error;
}
}
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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);
}
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());
}
}
}
private boolean isScriptResultTrue(Object groovyResult) {
return groovyResult.equals(true) || groovyResult.toString().trim().toLowerCase().equals("true");
}
private void checkValueOf(Config columnConfig, String value, ValidationError error) {
List<String> stringList = getStringList(columnConfig, "value of");
if (stringList != null) {
if (!stringList.contains(value)) {
String commaSeparated = stringList.stream().collect(joining(", "));
error.add("validation.message.value.of", value, commaSeparated);
}
}
}
private void checkBlankOrNull(Config columnConfig, String value, ValidationError error) {
if (getBoolean(columnConfig, "not empty")) {
if (isBlankOrNull(value)) {
error.add("validation.message.not.empty");
}
}
}
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");
if (minLength != null) {
if (!minLength(value, minLength)) {
error.add("validation.message.min.length", minLength.toString());
}
}
}
private void checkMaxLength(Config columnConfig, String value, ValidationError error) {
Integer maxLength = getInteger(columnConfig, "maxlength");
if (maxLength != null) {
if (!maxLength(value, maxLength)) {
error.add("validation.message.max.length", maxLength.toString());
}
}
}
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");
if (regexp != null && !regexp.trim().isEmpty()) {
if (!matchRegexp(value, regexp)) {
error.add("validation.message.regexp", regexp);
}
}
}
private Config getColumnSectionConfig() {
return validationConfig.hasPath("columns") ? validationConfig.getConfig("columns") : null;
}
private Config getColumnConfig(Config columnSectionConfig, String column) {
return columnSectionConfig.hasPath(column) ? columnSectionConfig.getConfig(column) : null;
}
private String getString(Config columnConfig, String path) {
return columnConfig.hasPath(path) ? columnConfig.getString(path) : null;
}
private Integer getInteger(Config columnConfig, String path) {
return columnConfig.hasPath(path) ? columnConfig.getInt(path) : null;
}
private boolean getBoolean(Config columnConfig, String path) {
return columnConfig.hasPath(path) && columnConfig.getBoolean(path);
}
private List<String> getStringList(Config columnConfig, String path) {
return columnConfig.hasPath(path) ? columnConfig.getStringList(path) : null;
}
public ValidationError isHeaderValid(String[] headerNames) {
ValidationError result = null;
if (validationConfig != null) {
if (validationConfig.hasPath("headers")) {
Config headerSectionConfig = validationConfig.getConfig("headers");
List<String> headerConfig = getStringList(headerSectionConfig, "list");
if (headerConfig != null) {
if (headerNames.length != headerConfig.size()) {
result = ValidationError.withoutLineNumber().add("validation.message.header.length",
Integer.toString(headerNames.length),
Integer.toString(headerConfig.size()));
return result;
}
ValidationError error = ValidationError.withoutLineNumber();
for(int i=0; i<headerConfig.size(); i++) {
String header = headerConfig.get(i);
if (!header.equals(headerNames[i])) {
error.add("validation.message.header.match",
Integer.toString(i),
header,
headerNames[i]);
}
}
if (!error.isEmpty()) {
result = error;
}
}
}
}
return result;
}
}
@@ -0,0 +1,77 @@
<?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.*?>
<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">
<children>
<Label text="3rd party software">
<VBox.margin>
<Insets top="8.0" />
</VBox.margin>
<font>
<Font size="18.0" />
</font>
</Label>
<ScrollPane fitToHeight="true" fitToWidth="true">
<content>
<GridPane hgap="4.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" vgap="4.0">
<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>
<children>
<Label text="junit" />
<Hyperlink onAction="#openLinkInBrowser" text="http://junit.org/" GridPane.columnIndex="1" />
<Label text="mockito" GridPane.rowIndex="1" />
<Hyperlink onAction="#openLinkInBrowser" text="http://mockito.org/" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="groovy" GridPane.rowIndex="2" />
<Hyperlink onAction="#openLinkInBrowser" text="http://www.groovy-lang.org/" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Label text="spring framework" GridPane.rowIndex="3" />
<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="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" />
</children>
<padding>
<Insets bottom="4.0" left="8.0" right="8.0" top="4.0" />
</padding>
</GridPane>
</content>
</ScrollPane>
<Label alignment="TOP_LEFT" text="The MIT License (MIT)">
<VBox.margin>
<Insets top="8.0" />
</VBox.margin>
<font>
<Font size="18.0" />
</font>
</Label>
<TextArea editable="false" prefHeight="200.0" prefWidth="200.0" text="Copyright (c) 2015 Andreas Billmann &lt;andreas.billmann@javafx.ninja&gt;&#10;&#10;Permission is hereby granted, free of charge, to any person obtaining a copy&#10;of this software and associated documentation files (the &quot;Software&quot;), to deal&#10;in the Software without restriction, including without limitation the rights&#10;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell&#10;copies of the Software, and to permit persons to whom the Software is&#10;furnished to do so, subject to the following conditions:&#10;&#10;The above copyright notice and this permission notice shall be included in&#10;all copies or substantial portions of the Software.&#10;&#10;&#10;&#10;THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR&#10;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,&#10;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE&#10;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER&#10;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,&#10;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN&#10;THE SOFTWARE." wrapText="true" />
</children>
<opaqueInsets>
<Insets />
</opaqueInsets>
<padding>
<Insets bottom="16.0" left="8.0" right="8.0" top="8.0" />
</padding>
</VBox>
@@ -0,0 +1,10 @@
application.name = SmartCSV.fx
application.version = 0.3
# 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
# resources
resource.main = ninja.javafx.smartcsv.fx.smartcsv
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?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" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
</rowConstraints>
<children>
<Label text="%preferences.quoteChar" />
<TextField fx:id="quoteChar" GridPane.columnIndex="1" />
<Label text="%preferences.delimiterChar" GridPane.rowIndex="1" />
<TextField fx:id="delimiterChar" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="%preferences.surroundingSpacesNeedQuotes" GridPane.rowIndex="2" />
<CheckBox fx:id="surroundingSpacesNeedQuotes" mnemonicParsing="false" text="" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Label text="%preferences.ignoreEmptyLines" GridPane.rowIndex="3" />
<CheckBox fx:id="ignoreEmptyLines" mnemonicParsing="false" text="" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<Label text="%preferences.quoteMode" GridPane.rowIndex="4" />
<ComboBox fx:id="quoteMode" prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="4" />
</children>
<padding>
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
</padding>
</GridPane>
@@ -0,0 +1,50 @@
.list-view {
-fx-background-color: -fx-background;
-fx-padding: 1;
}
.list-cell {
-fx-padding: 1.0em 1.0em 1.0em 1.0em;
}
.list-cell:odd {
-fx-background: -fx-control-inner-background-alt;
}
.list-cell:even {
-fx-background: -fx-control-inner-background;
}
.open-icon {
-glyph-name: "FILE_TEXT_ALT";
-glyph-size: 14px;
}
.config-icon {
-glyph-name: "CHECK";
-glyph-size: 14px;
}
.save-icon {
-glyph-name: "FLOPPY_ALT";
-glyph-size: 14px;
}
.exit-icon {
-glyph-name: "SIGN_OUT";
-glyph-size: 14px;
}
.info-icon {
-glyph-name: "INFO";
-glyph-size: 14px;
}
.error-title-icon {
-glyph-name: "EXCLAMATION_TRIANGLE";
-glyph-size: 14px;
}
.preferences-icon {
-glyph-name: "COG";
-glyph-size: 14px;
}
@@ -0,0 +1,135 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import de.jensd.fx.glyphs.fontawesome.*?>
<?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">
<top>
<VBox prefWidth="100.0" BorderPane.alignment="CENTER">
<children>
<MenuBar>
<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"/>
</graphic>
</MenuItem>
<MenuItem mnemonicParsing="false" onAction="#openConfig" text="%menu.open.config">
<graphic>
<FontAwesomeIconView styleClass="config-icon"/>
</graphic>
</MenuItem>
<SeparatorMenuItem mnemonicParsing="false"/>
<MenuItem fx:id="saveMenuItem" mnemonicParsing="false" onAction="#saveCsv" text="%menu.save" disable="true">
<graphic>
<FontAwesomeIconView styleClass="save-icon"/>
</graphic>
</MenuItem>
<MenuItem fx:id="saveAsMenuItem" mnemonicParsing="false" onAction="#saveAsCsv" text="%menu.save.as" disable="true">
<graphic>
<FontAwesomeIconView styleClass="save-icon"/>
</graphic>
</MenuItem>
<SeparatorMenuItem mnemonicParsing="false"/>
<MenuItem mnemonicParsing="false" onAction="#preferences" text="%menu.preferences">
<graphic>
<FontAwesomeIconView styleClass="preferences-icon"/>
</graphic>
</MenuItem>
<SeparatorMenuItem mnemonicParsing="false"/>
<MenuItem mnemonicParsing="false" onAction="#close" text="%menu.close">
<graphic>
<FontAwesomeIconView styleClass="exit-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"/>
</graphic>
</MenuItem>
</items>
</Menu>
</menus>
</MenuBar>
</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">
<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>
<stylesheets>
<URL value="@/ninja/javafx/smartcsv/fx/smartcsv.css"/>
</stylesheets>
<bottom>
<GridPane hgap="8.0" BorderPane.alignment="CENTER">
<columnConstraints>
<ColumnConstraints hgrow="NEVER" minWidth="10.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" prefWidth="100.0"/>
<ColumnConstraints hgrow="NEVER" minWidth="10.0"/>
<ColumnConstraints hgrow="NEVER" minWidth="10.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"/>
<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"/>
</children>
<BorderPane.margin>
<Insets top="4.0" left="8.0" bottom="4.0" right="8.0"/>
</BorderPane.margin>
</GridPane>
</bottom>
</BorderPane>
@@ -0,0 +1,47 @@
menu.open.csv = Open CSV File
menu.open.config = Open Validation Config
menu.save = Save
menu.save.as = Save As ...
menu.close = Close
menu.about = About
menu.file = File
menu.edit = Edit
menu.help = Help
menu.preferences = Preferences
title.validation.errors = Validation Errors:
stateline.csv = CSV:
stateline.configuration = Validation Configuration:
stateline.state = State:
state.changed = changed
state.unchanged = unchanged
dialog.exit.title = Close Application
dialog.exit.header.text = Do you want to close application?
dialog.exit.text = There are changes made to the csv file. If you close now, the changes are lost!
dialog.preferences.title = Preferences
dialog.preferences.header.text = Preferences
preferences.quoteChar = Quote character:
preferences.delimiterChar = Delimiter character:
preferences.ignoreEmptyLines = Ignore empty lines:
preferences.surroundingSpacesNeedQuotes = Surrounding spaces need quotes:
preferences.quoteMode = Quote mode:
# validaton messages
validation.message.not.empty = should not be empty
validation.message.integer = should be an integer
validation.message.double = should be a double
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
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.header.length = number of headers is not correct! there are {0} but there should be {1}
validation.message.header.match = header number {0} does not match "{1}" should be "{3}"
validation.message.value.of = Value {0} is not part of this list {1}
@@ -0,0 +1,55 @@
# ae = u00e4
# Ae = u00c4
# oe = u00f6
# Oe =u00d6
# ue = u00fc
# Ue = u00dc
# ss = u00df
menu.open.csv = CSV Datei \u00f6ffnen
menu.open.config = Pr\u00fcfkonfiguration \u00f6ffnen
menu.save = Speichern
menu.save.as = Speichern als ...
menu.close = Beenden
menu.about = \u00dcber ...
menu.file = Datei
menu.edit = Bearbeiten
menu.help = Hilfe
menu.preferences = Einstellungen
title.validation.errors = Fehler in der Datei:
stateline.csv = CSV:
stateline.configuration = Pr\u00fcfkonfiguration:
stateline.state = Status:
state.changed = Ge\u00e4ndert
state.unchanged = Unver\u00e4ndert
dialog.preferences.title = Eigenschaften
dialog.preferences.header.text = Eigenschaften
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.
preferences.quoteChar = Einfassungszeichen:
preferences.delimiterChar = Trennzeichen:
preferences.ignoreEmptyLines = Leere Zeilen ignorieren:
preferences.surroundingSpacesNeedQuotes = Leerzeichen einfassen:
preferences.quoteMode = Einfassungsmodus:
# validaton messages
validation.message.not.empty = Darf nicht leer sein.
validation.message.integer = Muss eine Zahl sein.
validation.message.double = Muss eine Gleitkommazahl 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"
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.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
@@ -0,0 +1,103 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.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.*;
/**
* unit test for the csv model
*/
public class CSVModelTest {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constants
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static final String TESTHEADER = "TESTHEADER";
static final String TESTVALUE = "TESTVALUE";
static final String FILEPATH = "filepath";
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// subject under test
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CSVModel sut = new CSVModel();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Test
public void fresh_model_has_empty_rows() {
// assertion
assertThat(sut.getRows(), empty());
}
@Test
public void adds_a_new_row_into_row_list() {
// execution
CSVRow newRow = sut.addRow();
// assertion
assertThat(sut.getRows(), contains(newRow));
}
@Test
public void new_row_has_last_index_of_list_as_rownumber() {
// execution
CSVRow newRow = sut.addRow();
// assertion
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
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void setup_model_with_one_row_one_column_and_value() {
sut.setHeader(new String[] {TESTHEADER});
sut.addRow().addValue(TESTHEADER, TESTVALUE);
}
}
@@ -0,0 +1,43 @@
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;
/**
* unit test for row class
*/
public class CSVRowTest {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constants
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static final String COLUMN = "COLUMN";
static final String VALUE = "VALUE";
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// subject under test
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CSVRow sut = new CSVRow();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Test
public void adds_column_and_value_to_row() {
// execution
sut.addValue(COLUMN, VALUE);
// assertion
assertThat(sut.getColumns(), hasKey(COLUMN));
assertThat(sut.getColumns().get(COLUMN).get().getValue(), is(VALUE));
}
}
@@ -0,0 +1,60 @@
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());
}
}
@@ -0,0 +1,62 @@
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;
}
}
@@ -0,0 +1,116 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import com.typesafe.config.Config;
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 org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* unit test for header validator
*/
@RunWith(Parameterized.class)
public class HeaderValidationTest {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// parameters
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private Config config;
private Boolean expectedResult;
private List<ValidationMessage> expectedErrors;
private String[] headerNames;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// subject under test
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private Validator sut;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// parameterized constructor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public HeaderValidationTest(String[] configHeaderNames,
String[] headerNames,
Boolean expectedResult,
List<ValidationMessage> expectedErrors) {
this.config = headerSectionConfig(configHeaderNames);
this.headerNames = headerNames;
this.expectedResult = expectedResult;
this.expectedErrors = expectedErrors;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// init
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Before
public void initialize() {
sut = new Validator(config);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Test
public void validation() {
// execution
ValidationError result = sut.isHeaderValid(headerNames);
// assertion
assertThat(result == null, is(expectedResult));
if (!expectedResult) {
assertTrue(result.getMessages().containsAll(expectedErrors));
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// parameters for tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@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")) }
});
}
}
@@ -0,0 +1,113 @@
package ninja.javafx.smartcsv.validation;
import com.typesafe.config.Config;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Collection;
import static java.util.Arrays.asList;
import static ninja.javafx.smartcsv.validation.ConfigMock.columnSectionConfig;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
/**
* unit test for validator
*/
@RunWith(Parameterized.class)
public class ValidatorTest {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// parameters
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private Config config;
private String column;
private String value;
private Boolean expectedResult;
private ValidationMessage expectedError;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// subject under test
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private Validator sut;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// parameterized constructor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public ValidatorTest(String configcolumn,
String configValidation,
Object configValue,
String column,
String value,
Boolean expectedResult,
ValidationMessage expectedError) {
this.config = columnSectionConfig(configcolumn, configValidation, configValue);
this.column = column;
this.value = value;
this.expectedResult = expectedResult;
this.expectedError = expectedError;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// init
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Before
public void initialize() {
sut = new Validator(config);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Test
public void validation() {
// execution
ValidationError result = sut.isValid(column, value, 0);
// assertion
assertThat(result == null, is(expectedResult));
if (!expectedResult) {
assertThat(result.getMessages(), contains(expectedError));
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// parameters for tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@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") },
});
}
}
-116
View File
@@ -1,116 +0,0 @@
/*
Copyright 2014 GitHub Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.pl-c /* comment */ {
color: #969896;
}
.pl-c1 /* constant, markup.raw, meta.diff.header, meta.module-reference, meta.property-name, support, support.constant, support.variable, variable.other.constant */,
.pl-s .pl-v /* string variable */ {
color: #0086b3;
}
.pl-e /* entity */,
.pl-en /* entity.name */ {
color: #795da3;
}
.pl-s .pl-s1 /* string source */,
.pl-smi /* storage.modifier.import, storage.modifier.package, storage.type.java, variable.other, variable.parameter.function */ {
color: #333;
}
.pl-ent /* entity.name.tag */ {
color: #63a35c;
}
.pl-k /* keyword, storage, storage.type */ {
color: #a71d5d;
}
.pl-pds /* punctuation.definition.string, string.regexp.character-class */,
.pl-s /* string */,
.pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */,
.pl-sr /* string.regexp */,
.pl-sr .pl-cce /* string.regexp constant.character.escape */,
.pl-sr .pl-sra /* string.regexp string.regexp.arbitrary-repitition */,
.pl-sr .pl-sre /* string.regexp source.ruby.embedded */ {
color: #183691;
}
.pl-v /* variable */ {
color: #ed6a43;
}
.pl-id /* invalid.deprecated */ {
color: #b52a1d;
}
.pl-ii /* invalid.illegal */ {
background-color: #b52a1d;
color: #f8f8f8;
}
.pl-sr .pl-cce /* string.regexp constant.character.escape */ {
color: #63a35c;
font-weight: bold;
}
.pl-ml /* markup.list */ {
color: #693a17;
}
.pl-mh /* markup.heading */,
.pl-mh .pl-en /* markup.heading entity.name */,
.pl-ms /* meta.separator */ {
color: #1d3e81;
font-weight: bold;
}
.pl-mq /* markup.quote */ {
color: #008080;
}
.pl-mi /* markup.italic */ {
color: #333;
font-style: italic;
}
.pl-mb /* markup.bold */ {
color: #333;
font-weight: bold;
}
.pl-md /* markup.deleted, meta.diff.header.from-file */ {
background-color: #ffecec;
color: #bd2c00;
}
.pl-mi1 /* markup.inserted, meta.diff.header.to-file */ {
background-color: #eaffea;
color: #55a532;
}
.pl-mdr /* meta.diff.range */ {
color: #795da3;
font-weight: bold;
}
.pl-mo /* meta.output */ {
color: #1d3e81;
}
-425
View File
@@ -1,425 +0,0 @@
/*******************************************************************************
Slate Theme for GitHub Pages
by Jason Costello, @jsncostello
*******************************************************************************/
@import url(github-light.css);
/*******************************************************************************
MeyerWeb Reset
*******************************************************************************/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
ol, ul {
list-style: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/*******************************************************************************
Theme Styles
*******************************************************************************/
body {
box-sizing: border-box;
color:#373737;
background: #212121;
font-size: 16px;
font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4, h5, h6 {
margin: 10px 0;
font-weight: 700;
color:#222222;
font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif;
letter-spacing: -1px;
}
h1 {
font-size: 36px;
font-weight: 700;
}
h2 {
padding-bottom: 10px;
font-size: 32px;
background: url('../images/bg_hr.png') repeat-x bottom;
}
h3 {
font-size: 24px;
}
h4 {
font-size: 21px;
}
h5 {
font-size: 18px;
}
h6 {
font-size: 16px;
}
p {
margin: 10px 0 15px 0;
}
footer p {
color: #f2f2f2;
}
a {
text-decoration: none;
color: #007edf;
text-shadow: none;
transition: color 0.5s ease;
transition: text-shadow 0.5s ease;
-webkit-transition: color 0.5s ease;
-webkit-transition: text-shadow 0.5s ease;
-moz-transition: color 0.5s ease;
-moz-transition: text-shadow 0.5s ease;
-o-transition: color 0.5s ease;
-o-transition: text-shadow 0.5s ease;
-ms-transition: color 0.5s ease;
-ms-transition: text-shadow 0.5s ease;
}
a:hover, a:focus {text-decoration: underline;}
footer a {
color: #F2F2F2;
text-decoration: underline;
}
em {
font-style: italic;
}
strong {
font-weight: bold;
}
img {
position: relative;
margin: 0 auto;
max-width: 739px;
padding: 5px;
margin: 10px 0 10px 0;
border: 1px solid #ebebeb;
box-shadow: 0 0 5px #ebebeb;
-webkit-box-shadow: 0 0 5px #ebebeb;
-moz-box-shadow: 0 0 5px #ebebeb;
-o-box-shadow: 0 0 5px #ebebeb;
-ms-box-shadow: 0 0 5px #ebebeb;
}
p img {
display: inline;
margin: 0;
padding: 0;
vertical-align: middle;
text-align: center;
border: none;
}
pre, code {
width: 100%;
color: #222;
background-color: #fff;
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
font-size: 14px;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
}
pre {
width: 100%;
padding: 10px;
box-shadow: 0 0 10px rgba(0,0,0,.1);
overflow: auto;
}
code {
padding: 3px;
margin: 0 3px;
box-shadow: 0 0 10px rgba(0,0,0,.1);
}
pre code {
display: block;
box-shadow: none;
}
blockquote {
color: #666;
margin-bottom: 20px;
padding: 0 0 0 20px;
border-left: 3px solid #bbb;
}
ul, ol, dl {
margin-bottom: 15px
}
ul {
list-style-position: inside;
list-style: disc;
padding-left: 20px;
}
ol {
list-style-position: inside;
list-style: decimal;
padding-left: 20px;
}
dl dt {
font-weight: bold;
}
dl dd {
padding-left: 20px;
font-style: italic;
}
dl p {
padding-left: 20px;
font-style: italic;
}
hr {
height: 1px;
margin-bottom: 5px;
border: none;
background: url('../images/bg_hr.png') repeat-x center;
}
table {
border: 1px solid #373737;
margin-bottom: 20px;
text-align: left;
}
th {
font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif;
padding: 10px;
background: #373737;
color: #fff;
}
td {
padding: 10px;
border: 1px solid #373737;
}
form {
background: #f2f2f2;
padding: 20px;
}
/*******************************************************************************
Full-Width Styles
*******************************************************************************/
.outer {
width: 100%;
}
.inner {
position: relative;
max-width: 640px;
padding: 20px 10px;
margin: 0 auto;
}
#forkme_banner {
display: block;
position: absolute;
top:0;
right: 10px;
z-index: 10;
padding: 10px 50px 10px 10px;
color: #fff;
background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%;
font-weight: 700;
box-shadow: 0 0 10px rgba(0,0,0,.5);
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
#header_wrap {
background: #212121;
background: -moz-linear-gradient(top, #373737, #212121);
background: -webkit-linear-gradient(top, #373737, #212121);
background: -ms-linear-gradient(top, #373737, #212121);
background: -o-linear-gradient(top, #373737, #212121);
background: linear-gradient(top, #373737, #212121);
}
#header_wrap .inner {
padding: 50px 10px 30px 10px;
}
#project_title {
margin: 0;
color: #fff;
font-size: 42px;
font-weight: 700;
text-shadow: #111 0px 0px 10px;
}
#project_tagline {
color: #fff;
font-size: 24px;
font-weight: 300;
background: none;
text-shadow: #111 0px 0px 10px;
}
#downloads {
position: absolute;
width: 210px;
z-index: 10;
bottom: -40px;
right: 0;
height: 70px;
background: url('../images/icon_download.png') no-repeat 0% 90%;
}
.zip_download_link {
display: block;
float: right;
width: 90px;
height:70px;
text-indent: -5000px;
overflow: hidden;
background: url(../images/sprite_download.png) no-repeat bottom left;
}
.tar_download_link {
display: block;
float: right;
width: 90px;
height:70px;
text-indent: -5000px;
overflow: hidden;
background: url(../images/sprite_download.png) no-repeat bottom right;
margin-left: 10px;
}
.zip_download_link:hover {
background: url(../images/sprite_download.png) no-repeat top left;
}
.tar_download_link:hover {
background: url(../images/sprite_download.png) no-repeat top right;
}
#main_content_wrap {
background: #f2f2f2;
border-top: 1px solid #111;
border-bottom: 1px solid #111;
}
#main_content {
padding-top: 40px;
}
#footer_wrap {
background: #212121;
}
/*******************************************************************************
Small Device Styles
*******************************************************************************/
@media screen and (max-width: 480px) {
body {
font-size:14px;
}
#downloads {
display: none;
}
.inner {
min-width: 320px;
max-width: 480px;
}
#project_title {
font-size: 32px;
}
h1 {
font-size: 28px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 21px;
}
h4 {
font-size: 18px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 12px;
}
code, pre {
min-width: 320px;
max-width: 480px;
font-size: 11px;
}
}