22 Commits

Author SHA1 Message Date
Andreas Billmann 71a6e8de85 Update index.html 2021-11-22 22:24:45 +01:00
Andreas Billmann 4c6d07010c Update index.html 2019-10-25 21:07:50 +02:00
Andreas Billmann b2389bdec9 Update index.html 2019-10-22 23:11:04 +02:00
frosch95 993e409457 Update index.html 2019-10-03 21:21:23 +02:00
Andreas Billmann 3977b7c1e2 change binary reference to zip bundle 2018-04-22 09:46:28 +02:00
frosch95 64cd005bae added fxlauncher to project page 2016-10-06 21:36:01 +02:00
Andreas Billmann 9b53d9f73b Update index.html 2016-09-23 11:18:22 +02:00
Andreas Billmann fbf7f520a6 Update index.html 2016-09-23 11:17:53 +02:00
Andreas Billmann 6ae9fa1217 Update index.html 2016-09-23 11:17:11 +02:00
Andreas Billmann 67c10d7b46 Update index.html 2016-08-10 23:47:59 +02:00
Andreas Billmann 50295ad63d Update index.html 2016-08-08 17:21:28 +02:00
frosch95 a8bd0e23a3 Update index.html 2016-08-05 23:22:19 +02:00
frosch95 ac7e158608 Update index.html 2016-08-03 11:00:23 +02:00
frosch95 dbaa2a0465 Update index.html 2016-07-23 00:49:47 +02:00
frosch95 a6cff93771 Update index.html 2016-07-23 00:15:57 +02:00
frosch95 1d7c8177fd version 0.4 2016-07-23 00:06:39 +02:00
frosch95 c9a8a7802d Update index.html 2016-02-01 01:37:47 +01:00
frosch95 1aa1d34eb5 Update index.html
new video link added
2016-01-14 11:09:35 +01:00
frosch95 3011d2f144 Update index.html 2016-01-12 23:03:33 +01:00
frosch95 27a933e6bb Update index.html 2015-12-30 18:26:38 +01:00
frosch95 eb9548b2e7 Update index.html 2015-12-18 16:36:14 +01:00
frosch95 8e4705b2d4 Create gh-pages branch via GitHub 2015-12-18 13:29:26 +01:00
104 changed files with 652 additions and 7891 deletions
-21
View File
@@ -1,21 +0,0 @@
name: Build and Test with Gradle
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 25
uses: actions/setup-java@v1
with:
java-version: 25
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
- name: Test with Gradle
run: ./gradlew test
-77
View File
@@ -1,77 +0,0 @@
# 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
smartcsv.log
-28
View File
@@ -1,28 +0,0 @@
The MIT License (MIT)
------------------------------------------------------------------------------------------------------------------------
Copyright (c) 2015-2021 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.
-51
View File
@@ -1,51 +0,0 @@
# SmartCSV.fx
![Build and Test](https://github.com/frosch95/SmartCSV.fx/workflows/Build%20and%20Test%20with%20Gradle/badge.svg) ![GitHub All Releases](https://img.shields.io/github/downloads/frosch95/SmartCSV.fx/total) ![GitHub](https://img.shields.io/github/license/frosch95/SmartCSV.fx) ![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/frosch95/SmartCSV.fx?label=version) ![GitHub Release Date](https://img.shields.io/github/release-date/frosch95/SmartCSV.fx)
## Description
A simple JavaFX application to load, save and edit a CSV file and provide a [JSON Table Schema](http://specs.frictionlessdata.io/json-table-schema/) for columns to check the values in the columns.
## Motivation
At work I have the need to fix wrong CSV files from customers. It is hard to find the errors and fix them in a texteditor,
even in a "normal" CSV editor. So I decided to write this simple JavaFX application.
## Video
[![short video about the application](http://img.youtube.com/vi/eUh_WLx1OwI/0.jpg)](https://youtu.be/eUh_WLx1OwI)
## Links
[GitHub Page](http://frosch95.github.io/SmartCSV.fx/)
[Wiki & Documentation](https://github.com/frosch95/SmartCSV.fx/wiki)
binary distribution of the [latest release (1.5.0)](https://github.com/frosch95/SmartCSV.fx/releases/download/1.5.0/SmartCSV.fx-1.5.0.zip)
## Talks
[Introduction](http://javafx.ninja/talks/introduction/)
## License
### The MIT License (MIT)
Copyright (c) 2015-2020 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.
-63
View File
@@ -1,63 +0,0 @@
plugins {
id 'idea'
id 'java'
id 'groovy'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.14'
id 'com.github.ben-manes.versions' version '0.48.0'
}
repositories {
mavenCentral()
}
apply plugin: 'java'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(25)
}
}
javafx {
version = "25"
modules = [ 'javafx.controls', 'javafx.fxml' ]
}
dependencies {
// updated testing libraries
testImplementation group: 'org.junit.platform', name: 'junit-platform-launcher', version: '6.0.0'
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '6.0.0'
testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '6.0.0'
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-params', version: '6.0.0'
testImplementation group: 'org.hamcrest', name: 'hamcrest', version: '3.0'
testImplementation group: 'org.mockito', name: 'mockito-core', version:'5.20.0'
// runtime libraries - bumped to recent stable versions where compatible
implementation group: 'org.apache.groovy', name: 'groovy', version: '5.0.2'
implementation group: 'org.springframework', name: 'spring-context', version: '6.2.12'
implementation group: 'de.siegmar', name: 'fastcsv', version: '4.1.0'
implementation group: 'commons-validator', name: 'commons-validator', version: '1.10.0'
implementation group: 'de.jensd', name: 'fontawesomefx-commons', version: '9.1.2'
implementation group: 'de.jensd', name: 'fontawesomefx-fontawesome', version: '4.7.0-9.1.2'
implementation group: 'de.jensd', name: 'fontawesomefx-materialdesignfont', version: '2.0.26-9.1.2'
implementation group: 'de.jensd', name: 'fontawesomefx-materialicons', version: '2.2.0-9.1.2'
implementation group: 'org.controlsfx', name: 'controlsfx', version: '11.2.2'
implementation group: 'com.google.code.gson', name: 'gson', version: '2.13.2'
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.25.2'
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.25.2'
implementation group: 'org.fxmisc.richtext', name: 'richtextfx', version: '0.11.6'
}
test {
useJUnitPlatform()
}
group 'ninja.javafx'
version '1.5.0'
application {
mainClass = 'ninja.javafx.smartcsv.Main'
applicationDefaultJvmArgs = ["--enable-native-access=javafx.graphics"]
}
Binary file not shown.
-5
View File
@@ -1,5 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
-172
View File
@@ -1,172 +0,0 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
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" -a "$nonstop" = "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"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
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
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
Vendored
-84
View File
@@ -1,84 +0,0 @@
@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
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
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 Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_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=%*
: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.

After

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

+109
View File
@@ -0,0 +1,109 @@
<!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
@@ -0,0 +1 @@
console.log('This would be the main JS file.');
+1
View File
@@ -0,0 +1 @@
{"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
@@ -1,2 +0,0 @@
rootProject.name = 'SmartCSV.fx'
@@ -1,38 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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<E> {
E getContent();
void read(File filename) throws IOException;
}
@@ -1,38 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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<E> {
void setContent(E content);
void write(File filename) throws IOException;
}
@@ -1,36 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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 ninja.javafx.smartcsv.fx.SmartCSV;
public class Main {
public static void main(String[] args) {
// workaround for module problem
SmartCSV.main(args);
}
}
@@ -1,54 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.preferences.Preferences;
import static ninja.javafx.smartcsv.preferences.Preferences.defaultPreferences;
/**
*
*/
public class CSVConfigurable {
protected Preferences csvPreference;
protected String fileEncoding;
public CSVConfigurable() {
csvPreference = defaultPreferences();
}
public void setCsvPreference(Preferences csvPreference) {
this.csvPreference = csvPreference;
}
public void setFileEncoding(String fileEncoding) {
this.fileEncoding = fileEncoding;
}
}
@@ -1,90 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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 de.siegmar.fastcsv.reader.CsvReader;
import de.siegmar.fastcsv.reader.NamedCsvRecord;
import ninja.javafx.smartcsv.FileReader;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
/**
* reads the csv file and stores the values in csv model
*/
public class CSVFileReader extends CSVConfigurable implements FileReader<CSVModel> {
private CSVModel model;
@Override
public void read(File file) throws IOException {
System.out.println(csvPreference);
try (var csv = getNamedCsvReader(file)) {
model = new CSVModel();
// the header columns are used as the keys to the Map
var firstRow = csv.stream().findFirst();
if (firstRow.isEmpty()) {
return;
}
var header = firstRow.get().getHeader().toArray(String[]::new);
model.setHeader(header);
csv.forEach(csvRow -> {
var row = model.addRow();
for (String column : header) {
model.addValue(row, column, csvRow.getField(column));
}
});
} catch (IOException ex) {
// TODO perhaps a custom NinjaException that can properly identify and localize the exception message
// is this a file not found? is this a corrupt csv? etc
throw new IOException("Failed to read " + file + ": " + ex.getMessage(), ex);
}
}
private CsvReader<NamedCsvRecord> getNamedCsvReader(File file) throws IOException {
var builder = CsvReader.builder()
.fieldSeparator(csvPreference.delimiterChar());
if (csvPreference.quoteChar() != null) {
builder.quoteCharacter(csvPreference.quoteChar());
}
return builder.ofNamedCsvRecord(file.toPath(), Charset.forName(fileEncoding));
}
public CSVModel getContent() {
return model;
}
}
@@ -1,81 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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 de.siegmar.fastcsv.writer.CsvWriter;
import de.siegmar.fastcsv.writer.QuoteStrategies;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import static java.util.stream.Collectors.toList;
/**
* filewriter for the csv
*/
public class CSVFileWriter extends CSVConfigurable implements ninja.javafx.smartcsv.FileWriter<CSVModel> {
private CSVModel model;
public void setContent(CSVModel model) {
this.model = model;
}
@Override
public void write(File filename) throws IOException {
try (var writer = getCsvWriter(filename)){
writer.writeRecord(model.getHeader());
for(CSVRow row: model.getRows()) {
writer.writeRecord(convertMapFromModel(row));
}
}
}
private CsvWriter getCsvWriter(File filename) throws IOException {
var writer = CsvWriter.builder().fieldSeparator(csvPreference.delimiterChar());
if (csvPreference.quoteChar() != null) {
writer.quoteCharacter(csvPreference.quoteChar());
writer.quoteStrategy(QuoteStrategies.ALWAYS);
}
return writer.build(filename.toPath(), Charset.forName(fileEncoding));
}
/**
* 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 List<String> convertMapFromModel(CSVRow row) {
return row.getColumns().values().stream().map(v -> v.get().getValue())
.collect(toList());
}
}
@@ -1,96 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.export;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import java.io.File;
import java.io.StringWriter;
import java.nio.file.Files;
import java.util.ResourceBundle;
import static java.text.MessageFormat.format;
import static ninja.javafx.smartcsv.fx.util.I18nValidationUtil.getI18nValidatioMessage;
/**
* this class exports the error messages into a log file
*/
@org.springframework.stereotype.Service
public class ErrorExport extends Service {
private CSVModel model;
private File file;
private ResourceBundle resourceBundle;
private String csvFilename;
public void setCsvFilename(String csvFilename) {
this.csvFilename = csvFilename;
}
public void setResourceBundle(ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
}
public void setModel(CSVModel model) {
this.model = model;
}
public void setFile(File file) {
this.file = file;
}
@Override
protected Task createTask() {
return new Task() {
@Override
protected Void call() throws Exception {
try {
StringWriter log = new StringWriter();
log.append(
format(resourceBundle.getString("log.header.message"),
csvFilename,
Integer.toString(model.getValidationError().size()))).append("\n\n");
model.getValidationError().forEach(error ->
log.append(
format(resourceBundle.getString("log.message"),
error.getLineNumber().toString(),
error.getColumn(),
getI18nValidatioMessage(resourceBundle, error))).append("\n")
);
Files.write(file.toPath(), log.toString().getBytes());
} catch (Throwable ex) {
ex.printStackTrace();
}
return null;
}
};
}
}
@@ -1,104 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.files;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import ninja.javafx.smartcsv.FileReader;
import ninja.javafx.smartcsv.FileWriter;
import java.io.File;
import java.io.IOException;
/**
* This class stores files and their state
* @author abi
*/
public class FileStorage<E> {
private FileReader<E> reader;
private FileWriter<E> writer;
public FileStorage(FileReader<E> reader, FileWriter<E> writer) {
this.reader = reader;
this.writer = writer;
}
private BooleanProperty fileChanged = new SimpleBooleanProperty(true);
private ObjectProperty<File> file = new SimpleObjectProperty<>();
private ObjectProperty<E> content = new SimpleObjectProperty<>();
public boolean isFileChanged() {
return fileChanged.get();
}
public BooleanProperty fileChangedProperty() {
return fileChanged;
}
public void setFileChanged(boolean fileChanged) {
this.fileChanged.set(fileChanged);
}
public File getFile() {
return file.get();
}
public ObjectProperty<File> fileProperty() {
return file;
}
public void setFile(File file) {
this.file.set(file);
}
public E getContent() {
return content.get();
}
public ObjectProperty<E> contentProperty() {
return content;
}
public void setContent(E content) {
this.content.set(content);
}
public void load() throws IOException {
reader.read(file.get());
setContent(reader.getContent());
setFileChanged(false);
}
public void save() throws IOException {
writer.setContent(content.get());
writer.write(file.get());
setFileChanged(false);
}
}
@@ -1,72 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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;
}
}
@@ -1,106 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
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());
var defaultThemeCss = getClass().getResource("/ninja/javafx/smartcsv/fx/smartcsv.css").toExternalForm();
scene.getRoot().getStylesheets().add(defaultThemeCss);
primaryStage.setScene(scene);
primaryStage.setTitle(String.format("%s %s", name, version));
primaryStage.getIcons().add(new Image(SmartCSV.class.getResourceAsStream("/ninja/javafx/smartcsv/icon/logo.png")));
primaryStage.show();
primaryStage.setMaximized(true);
primaryStage.setOnCloseRequest(event -> {
if (!smartCVSController.canExit()) {
event.consume();
} else {
exit();
}
});
}
}
@@ -1,802 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.InvalidationListener;
import javafx.beans.binding.Bindings;
import javafx.collections.ListChangeListener;
import javafx.collections.WeakListChangeListener;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser;
import ninja.javafx.smartcsv.csv.CSVFileReader;
import ninja.javafx.smartcsv.csv.CSVFileWriter;
import ninja.javafx.smartcsv.export.ErrorExport;
import ninja.javafx.smartcsv.files.FileStorage;
import ninja.javafx.smartcsv.fx.about.AboutController;
import ninja.javafx.smartcsv.fx.list.ErrorSideBar;
import ninja.javafx.smartcsv.fx.list.GotoLineDialog;
import ninja.javafx.smartcsv.fx.preferences.PreferencesController;
import ninja.javafx.smartcsv.fx.table.ObservableMapValueFactory;
import ninja.javafx.smartcsv.fx.table.ValidationCellFactory;
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.JavaFxUtils;
import ninja.javafx.smartcsv.fx.util.LoadFileService;
import ninja.javafx.smartcsv.fx.util.SaveFileService;
import ninja.javafx.smartcsv.fx.validation.ValidationEditorController;
import ninja.javafx.smartcsv.preferences.*;
import ninja.javafx.smartcsv.validation.ValidationError;
import ninja.javafx.smartcsv.validation.ValidationFileReader;
import ninja.javafx.smartcsv.validation.ValidationFileWriter;
import ninja.javafx.smartcsv.validation.configuration.ValidationConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Optional;
import java.util.ResourceBundle;
import static java.lang.Math.max;
import static java.text.MessageFormat.format;
import static javafx.application.Platform.exit;
import static javafx.application.Platform.runLater;
import static javafx.beans.binding.Bindings.*;
import static javafx.scene.layout.AnchorPane.*;
import static ninja.javafx.smartcsv.preferences.Preferences.defaultPreferences;
/**
* 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");
private static final File ENCODING_FILE = new File(System.getProperty("user.home") +
File.separator +
".SmartCSV.fx" +
File.separator +
"encoding.json");
public static final String CSV_FILTER_TEXT = "CSV files (*.csv)";
public static final String CSV_FILTER_EXTENSION = "*.csv";
public static final String JSON_FILTER_TEXT = "JSON files (*.json)";
public static final String JSON_FILTER_EXTENSION = "*.json";
public static final String EXPORT_LOG_FILTER_TEXT = "Error log files (*.log)";
public static final String EXPORT_LOG_FILTER_EXTENSION = "*.log";
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// injections
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Autowired
private AboutController aboutController;
@Autowired
private PreferencesController preferencesController;
@Autowired
private ValidationEditorController validationEditorController;
@Autowired
private LoadFileService loadFileService;
@Autowired
private SaveFileService saveFileService;
@Autowired
private ErrorExport errorExport;
@FXML
private BorderPane applicationPane;
@FXML
private Label csvName;
@FXML
private Label configurationName;
@FXML
private Label stateName;
@FXML
private AnchorPane tableWrapper;
@FXML
private MenuItem saveMenuItem;
@FXML
private MenuItem saveAsMenuItem;
@FXML
private MenuItem createConfigMenuItem;
@FXML
private MenuItem loadConfigMenuItem;
@FXML
private MenuItem saveConfigMenuItem;
@FXML
private MenuItem saveAsConfigMenuItem;
@FXML
private MenuItem deleteRowMenuItem;
@FXML
private MenuItem addRowMenuItem;
@FXML
private MenuItem gotoLineMenuItem;
@FXML
private MenuItem exportMenuItem;
@FXML
private Button saveButton;
@FXML
private Button saveAsButton;
@FXML
private Button createConfigButton;
@FXML
private Button loadConfigButton;
@FXML
private Button saveConfigButton;
@FXML
private Button saveAsConfigButton;
@FXML
private Button deleteRowButton;
@FXML
private Button addRowButton;
@FXML
private Button exportButton;
@FXML
private Label currentLineNumber;
@FXML
private Label totalNumberOfLines;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// members
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private ValidationCellFactory cellFactory;
private TableView<CSVRow> tableView;
private ErrorSideBar errorSideBar;
private ResourceBundle resourceBundle;
private CSVFileReader csvFileReader = new CSVFileReader();
private CSVFileWriter csvFileWriter = new CSVFileWriter();
private FileStorage<CSVModel> currentCsvFile = new FileStorage<>(csvFileReader, csvFileWriter);
private FileStorage<ValidationConfiguration> currentConfigFile = new FileStorage<>(new ValidationFileReader(), new ValidationFileWriter());
private FileStorage<Preferences> csvPreferenceFile = new FileStorage<>(new PreferencesFileReader(), new PreferencesFileWriter());
private FileStorage<String> fileEncodingFile = new FileStorage<>(new EncodingFileReader(), new EncodingFileWriter());
private ListChangeListener<ValidationError> errorListListener = c -> tableView.refresh();
private WeakListChangeListener<ValidationError> weakErrorListListener = new WeakListChangeListener<>(errorListListener);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// init
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
public void initialize(URL location, ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
setupTableCellFactory();
setupErrorSideBar(resourceBundle);
bindMenuItemsToContentExistence(currentCsvFile, saveMenuItem, saveAsMenuItem, addRowMenuItem, gotoLineMenuItem, createConfigMenuItem, loadConfigMenuItem);
bindButtonsToContentExistence(currentCsvFile, saveButton, saveAsButton, addRowButton, createConfigButton, loadConfigButton);
bindMenuItemsToContentExistence(currentConfigFile, saveConfigMenuItem, saveAsConfigMenuItem);
bindButtonsToContentExistence(currentConfigFile, saveAsConfigButton, saveConfigButton);
bindCsvFileName();
bindConfigFileName();
csvPreferenceFile.setFile(PREFERENCES_FILE);
fileEncodingFile.setFile(ENCODING_FILE);
loadCsvPreferencesFromFile();
initDragAndDrop();
}
private void initDragAndDrop() {
tableWrapper.setOnDragOver(event -> {
Dragboard db = event.getDragboard();
if (event.getGestureSource() != tableWrapper
&& db.hasFiles()
&& db.getFiles().size() == 1
&& db.getFiles().get(0).getName().endsWith(".csv")) {
event.acceptTransferModes(TransferMode.COPY);
}
event.consume();
});
tableWrapper.setOnDragDropped(event -> {
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasFiles() && db.getFiles().size() == 1 && canOpen()) {
File file = db.getFiles().get(0);
openFile(currentCsvFile, file);
success = true;
}
/* let the source know whether the string was successfully
* transferred and used */
event.setDropCompleted(success);
});
}
private void loadEncodingFromFile() {
if (fileEncodingFile.getFile().exists()) {
useLoadFileService(fileEncodingFile, event -> setFileEncoding(fileEncodingFile.getContent()));
} else {
setFileEncoding(Charset.defaultCharset().name());
}
}
private void setFileEncoding(String content) {
preferencesController.setFileEncoding(content);
csvFileReader.setFileEncoding(content);
csvFileWriter.setFileEncoding(content);
}
private void setupErrorSideBar(ResourceBundle resourceBundle) {
errorSideBar = new ErrorSideBar(resourceBundle);
errorSideBar.selectedValidationErrorProperty().addListener((observable, oldValue, newValue) -> {
scrollToError(newValue);
});
applicationPane.setRight(errorSideBar);
}
private void setupTableCellFactory() {
cellFactory = new ValidationCellFactory(resourceBundle);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// setter
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Value("${fxml.smartcvs.view}")
@Override
public void setFxmlFilePath(String filePath) {
this.fxmlFilePath = filePath;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// actions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@FXML
public void openCsv(ActionEvent actionEvent) {
loadFile(CSV_FILTER_TEXT, CSV_FILTER_EXTENSION, "Open CSV", currentCsvFile);
}
@FXML
public void openConfig(ActionEvent actionEvent) {
loadFile(JSON_FILTER_TEXT, JSON_FILTER_EXTENSION, "Open Validation Configuration", currentConfigFile);
}
@FXML
public void createConfig(ActionEvent actionEvent) {
currentConfigFile.setContent(currentCsvFile.getContent().createValidationConfiguration());
currentConfigFile.setFile(null);
currentConfigFile.setFileChanged(true);
resetContent();
}
@FXML
public void saveCsv(ActionEvent actionEvent) {
useSaveFileService(currentCsvFile);
}
@FXML
public void saveAsCsv(ActionEvent actionEvent) {
saveFile(CSV_FILTER_TEXT, CSV_FILTER_EXTENSION, currentCsvFile);
}
@FXML
public void saveConfig(ActionEvent actionEvent) {
if (currentConfigFile.getFile() == null) {
saveAsConfig(actionEvent);
} else {
useSaveFileService(currentConfigFile);
}
}
@FXML
public void saveAsConfig(ActionEvent actionEvent) {
saveFile(JSON_FILTER_TEXT, JSON_FILTER_EXTENSION, currentConfigFile);
}
@FXML
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){
Preferences csvPreference = preferencesController.getCsvPreference();
setCsvPreference(csvPreference);
saveCsvPreferences(csvPreference);
String fileEncoding = CharsetHelper.getCharsetName(preferencesController.getFileEncoding());
setFileEncoding(fileEncoding);
saveFileEncoding(fileEncoding);
} else {
preferencesController.setCsvPreference(csvPreferenceFile.getContent());
preferencesController.setFileEncoding(fileEncodingFile.getContent());
}
}
private void saveFileEncoding(String fileEncoding) {
try {
createFileEncodingFile();
fileEncodingFile.setContent(fileEncoding);
useSaveFileService(fileEncodingFile);
} catch (IOException e) {
e.printStackTrace();
}
}
private void createFileEncodingFile() throws IOException {
if (!fileEncodingFile.getFile().exists()) {
createPreferencesFileFolder();
fileEncodingFile.getFile().createNewFile();
}
}
@FXML
public void deleteRow(ActionEvent actionEvent) {
currentCsvFile.getContent().getRows().removeAll(tableView.getSelectionModel().getSelectedItems());
currentCsvFile.setFileChanged(true);
resetContent();
}
@FXML
public void addRow(ActionEvent actionEvent) {
CSVRow row = currentCsvFile.getContent().addRow();
for (String column : currentCsvFile.getContent().getHeader()) {
currentCsvFile.getContent().addValue(row, column, "");
}
currentCsvFile.setFileChanged(true);
resetContent();
selectNewRow();
}
@FXML
public void gotoLine(ActionEvent actionEvent) {
int maxLineNumber = currentCsvFile.getContent().getRows().size();
GotoLineDialog dialog = new GotoLineDialog(maxLineNumber);
dialog.setTitle(resourceBundle.getString("dialog.goto.line.title"));
dialog.setHeaderText(format(resourceBundle.getString("dialog.goto.line.header.text"), maxLineNumber));
dialog.setContentText(resourceBundle.getString("dialog.goto.line.label"));
Optional<Integer> result = dialog.showAndWait();
if (result.isPresent()){
Integer lineNumber = result.get();
if (lineNumber != null) {
tableView.scrollTo(max(0, lineNumber - 2));
tableView.getSelectionModel().select(lineNumber - 1);
}
}
}
@FXML
public void export(ActionEvent actionEvent) {
final FileChooser fileChooser = new FileChooser();
//Set extension filter
final FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(EXPORT_LOG_FILTER_TEXT, EXPORT_LOG_FILTER_EXTENSION);
fileChooser.getExtensionFilters().add(extFilter);
fileChooser.setTitle("Save");
//Show open file dialog
File file = fileChooser.showSaveDialog(applicationPane.getScene().getWindow());
if (file != null) {
errorExport.setCsvFilename(currentCsvFile.getFile().getName());
errorExport.setModel(currentCsvFile.getContent());
errorExport.setFile(file);
errorExport.setResourceBundle(resourceBundle);
errorExport.restart();
}
}
public boolean canExit() {
boolean canExit = true;
if (currentCsvFile.getContent() != null && currentCsvFile.isFileChanged()) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle(resourceBundle.getString("dialog.exit.title"));
alert.setHeaderText(resourceBundle.getString("dialog.exit.header.text"));
alert.setContentText(resourceBundle.getString("dialog.exit.text"));
Optional<ButtonType> result = alert.showAndWait();
if (result.get() != ButtonType.OK){
canExit = false;
}
}
return canExit;
}
private boolean canOpen() {
boolean canOpen = true;
if (currentCsvFile.getContent() != null && currentCsvFile.isFileChanged()) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle(resourceBundle.getString("dialog.changes.title"));
alert.setHeaderText(resourceBundle.getString("dialog.changes.header.text"));
alert.setContentText(resourceBundle.getString("dialog.changes.text"));
Optional<ButtonType> result = alert.showAndWait();
if (result.get() != ButtonType.OK){
canOpen = false;
}
}
return canOpen;
}
public void showValidationEditor(String column) {
validationEditorController.setSelectedColumn(column);
validationEditorController.updateForm();
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setGraphic(null);
alert.setTitle(resourceBundle.getString("dialog.validation.rules.title"));
alert.setHeaderText(format(resourceBundle.getString("dialog.validation.rules.header"), column));
alert.getDialogPane().setContent(validationEditorController.getView());
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK){
runLater(() -> {
validationEditorController.updateConfiguration();
currentCsvFile.setFileChanged(true);
currentCsvFile.getContent().revalidate(column);
});
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void selectNewRow() {
int lastRow = tableView.getItems().size()-1;
tableView.scrollTo(lastRow);
tableView.requestFocus();
tableView.getSelectionModel().select(lastRow);
}
private void bindMenuItemsToContentExistence(FileStorage file, MenuItem... items) {
for (MenuItem item: items) {
item.disableProperty().bind(isNull(file.contentProperty()));
}
}
private void bindButtonsToContentExistence(FileStorage file, Button... items) {
for (Button item: items) {
item.disableProperty().bind(isNull(file.contentProperty()));
}
}
private void bindMenuItemsToTableSelection(MenuItem... items) {
for (MenuItem item: items) {
item.disableProperty().bind(lessThan(tableView.getSelectionModel().selectedIndexProperty(), 0));
}
}
private void bindButtonsToTableSelection(Button... items) {
for (Button item: items) {
item.disableProperty().bind(lessThan(tableView.getSelectionModel().selectedIndexProperty(), 0));
}
}
private void bindCsvFileName() {
csvName.textProperty().bind(selectString(currentCsvFile.fileProperty(), "name"));
}
private void bindConfigFileName() {
configurationName.textProperty().bind(selectString(currentConfigFile.fileProperty(), "name"));
}
private void bindLineNumber() {
currentLineNumber.textProperty().bind(tableView.getSelectionModel().selectedIndexProperty().add(1).asString());
}
private void loadCsvPreferencesFromFile() {
if (csvPreferenceFile.getFile().exists()) {
useLoadFileService(csvPreferenceFile, event -> {
setCsvPreference(csvPreferenceFile.getContent());
loadEncodingFromFile();
});
} else {
setCsvPreference(defaultPreferences());
loadEncodingFromFile();
}
}
private void saveCsvPreferences(Preferences csvPreference) {
try {
createPreferenceFile();
csvPreferenceFile.setContent(csvPreference);
useSaveFileService(csvPreferenceFile);
} catch (IOException e) {
e.printStackTrace();
}
}
private void createPreferenceFile() throws IOException {
if (!csvPreferenceFile.getFile().exists()) {
createPreferencesFileFolder();
csvPreferenceFile.getFile().createNewFile();
}
}
private void createPreferencesFileFolder() {
if (!csvPreferenceFile.getFile().getParentFile().exists()) {
csvPreferenceFile.getFile().getParentFile().mkdir();
}
}
private void setCsvPreference(Preferences csvPreference) {
preferencesController.setCsvPreference(csvPreference);
csvFileReader.setCsvPreference(csvPreference);
csvFileWriter.setCsvPreference(csvPreference);
}
private void loadFile(String filterText,
String filter,
String title,
FileStorage storageFile) {
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 (storageFile.getFile() != null) {
fileChooser.setInitialDirectory(storageFile.getFile().getParentFile());
}
//Show open file dialog
File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow());
openFile(storageFile, file);
}
private void openFile(FileStorage storageFile, File file) {
if (file != null) {
File previousFile = storageFile.getFile();
storageFile.setFile(file);
useLoadFileService(storageFile, t -> resetContent(), () -> storageFile.setFile(previousFile));
}
}
private File saveFile(String filterText, String filter, FileStorage fileStorage) {
File file = fileStorage.getFile();
if (fileStorage.getContent() != null) {
final FileChooser fileChooser = new FileChooser();
//Set extension filter
final FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(filterText, filter);
fileChooser.getExtensionFilters().add(extFilter);
if (fileStorage.getFile() != null) {
fileChooser.setInitialDirectory(fileStorage.getFile().getParentFile());
fileChooser.setInitialFileName(fileStorage.getFile().getName());
}
fileChooser.setTitle("Save File");
//Show open file dialog
file = fileChooser.showSaveDialog(applicationPane.getScene().getWindow());
if (file != null) {
fileStorage.setFile(file);
useSaveFileService(fileStorage);
}
}
return file;
}
private void useLoadFileService(FileStorage<?> fileStorage, EventHandler<WorkerStateEvent> onSucceededHandler) {
useLoadFileService(fileStorage, onSucceededHandler, () -> {
// nothing to rollback
});
}
private void useLoadFileService(FileStorage<?> fileStorage, EventHandler<WorkerStateEvent> onSucceededHandler, Runnable rollbackAction) {
loadFileService.setFileStorage(fileStorage);
loadFileService.restart();
loadFileService.setOnSucceeded(onSucceededHandler);
loadFileService.setOnFailed(event -> JavaFxUtils.onServiceError(event, "LoadFileService Error", "Failed to load the file.", rollbackAction));
}
private void useSaveFileService(FileStorage<?> fileStorage) {
saveFileService.setFileStorage(fileStorage);
saveFileService.restart();
saveFileService.setOnSucceeded(t -> resetContent());
}
/**
* Creates new table view and add the new content
*/
private void resetContent() {
resetExportButtons();
if (currentCsvFile.getContent() != null) {
currentCsvFile.getContent().getValidationError().addListener(weakErrorListListener);
currentCsvFile.getContent().setValidationConfiguration(currentConfigFile.getContent());
validationEditorController.setValidationConfiguration(currentConfigFile.getContent());
tableView = new TableView<>();
bindLineNumber();
bindMenuItemsToTableSelection(deleteRowMenuItem);
bindButtonsToTableSelection(deleteRowButton);
for (String column : currentCsvFile.getContent().getHeader()) {
addColumn(column, tableView);
}
tableView.getColumns().addListener(
(InvalidationListener) observable -> currentCsvFile.getContent().setHeader(
tableView.getColumns().stream().map((x) -> x.getText()).toArray(String[]::new)));
tableView.getItems().setAll(currentCsvFile.getContent().getRows());
tableView.setEditable(true);
totalNumberOfLines.textProperty().setValue("" + currentCsvFile.getContent().getRows().size());
setBottomAnchor(tableView, 0.0);
setTopAnchor(tableView, 0.0);
setLeftAnchor(tableView, 0.0);
setRightAnchor(tableView, 0.0);
tableWrapper.getChildren().setAll(tableView);
errorSideBar.setModel(currentCsvFile.getContent());
binExportButtons();
}
}
private void binExportButtons() {
exportButton.disableProperty().bind(Bindings.isEmpty(currentCsvFile.getContent().getValidationError()));
exportMenuItem.disableProperty().bind(Bindings.isEmpty(currentCsvFile.getContent().getValidationError()));
}
private void resetExportButtons() {
exportButton.disableProperty().unbind();
exportMenuItem.disableProperty().unbind();
exportButton.disableProperty().setValue(true);
exportMenuItem.disableProperty().setValue(true);
}
/**
* Adds a column with the given name to the tableview
* @param header name of the column header
* @param tableView the tableview
*/
private void addColumn(final String header, TableView tableView) {
TableColumn column = new TableColumn(header);
column.setCellValueFactory(new ObservableMapValueFactory(header));
column.setCellFactory(cellFactory);
column.setEditable(true);
column.setSortable(false);
ContextMenu contextMenu = contextMenuForColumn(header);
column.setContextMenu(contextMenu);
column.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<CSVRow, CSVValue>>() {
@Override
public void handle(TableColumn.CellEditEvent<CSVRow, CSVValue> event) {
event.getTableView().getItems().get(event.getTablePosition().getRow()).
getColumns().get(header).setValue(event.getNewValue());
runLater(() -> {
currentCsvFile.setFileChanged(true);
});
}
});
tableView.getColumns().add(column);
}
private ContextMenu contextMenuForColumn(String header) {
ContextMenu contextMenu = new ContextMenu();
MenuItem editColumnRulesMenuItem = new MenuItem(resourceBundle.getString("context.menu.edit.column.rules"));
bindMenuItemsToContentExistence(currentConfigFile, editColumnRulesMenuItem);
editColumnRulesMenuItem.setOnAction(e -> showValidationEditor(header));
contextMenu.getItems().addAll(editColumnRulesMenuItem);
return contextMenu;
}
private void scrollToError(ValidationError entry) {
if (entry != null) {
if (entry.getLineNumber() != null) {
tableView.scrollTo(max(0, entry.getLineNumber() - 1));
tableView.getSelectionModel().select(entry.getLineNumber());
} else {
tableView.scrollTo(0);
}
}
}
}
@@ -1,68 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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;
}
}
@@ -1,173 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.list;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ListChangeListener;
import javafx.collections.WeakListChangeListener;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.validation.ValidationError;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.controlsfx.control.PopOver;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import static javafx.geometry.Pos.CENTER;
import static ninja.javafx.smartcsv.fx.util.ColorConstants.ERROR_COLOR;
import static ninja.javafx.smartcsv.fx.util.ColorConstants.OK_COLOR;
import static ninja.javafx.smartcsv.fx.util.I18nValidationUtil.getI18nValidatioMessageWithColumn;
/**
* clickable side bar with error markers
*/
public class ErrorSideBar extends Region {
private static final Logger logger = LogManager.getLogger(ErrorSideBar.class);
private static final double WIDTH = 20.0;
private static final int BORDER = 8;
private static final double STATUS_BLOCK_HEIGHT = WIDTH - BORDER;
private static final double STATUS_BLOCK_WIDTH = WIDTH - BORDER;
private static final double STATUS_BLOCK_OFFSET = WIDTH + BORDER / 2;
private ListChangeListener<ValidationError> errorListListener = c -> setErrorMarker();
private WeakListChangeListener<ValidationError> weakErrorListListener = new WeakListChangeListener<>(errorListListener);
private ObjectProperty<CSVModel> model = new SimpleObjectProperty<>();
private ObjectProperty<ValidationError> selectedValidationError = new SimpleObjectProperty<>();
private PopOver popOver = new PopOver();
private ResourceBundle resourceBundle;
private Region statusBlock;
public ErrorSideBar(ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
initPopOver();
setFixWidth();
addModelListener();
statusBlock = new Region();
statusBlock.setPrefSize(STATUS_BLOCK_WIDTH, STATUS_BLOCK_HEIGHT);
statusBlock.setLayoutY(BORDER / 2);
statusBlock.setLayoutX(BORDER / 2);
}
private void initPopOver() {
popOver.setAutoHide(true);
popOver.setArrowLocation(PopOver.ArrowLocation.RIGHT_CENTER);
}
public void setModel(CSVModel model) {
this.model.set(model);
}
public CSVModel getModel() {
return model.get();
}
public ObjectProperty<CSVModel> modelProperty() {
return model;
}
public ValidationError getSelectedValidationError() {
return selectedValidationError.get();
}
public ObjectProperty<ValidationError> selectedValidationErrorProperty() {
return selectedValidationError;
}
public void setSelectedValidationError(ValidationError selectedValidationError) {
this.selectedValidationError.set(selectedValidationError);
}
private void addModelListener() {
model.addListener((observable, oldValue, newValue) -> {
newValue.getValidationError().addListener(weakErrorListListener);
setErrorMarker();
});
}
private void setFixWidth() {
setMinWidth(WIDTH);
setPrefWidth(WIDTH);
setMaxWidth(WIDTH);
}
private void setErrorMarker() {
List<Region> errorMarkerList = new ArrayList<>();
errorMarkerList.add(statusBlock);
statusBlock.setStyle("-fx-background-color: " + OK_COLOR);
if (model.get() != null) {
List<ValidationError> errorList = model.get().getValidationError();
if (errorList != null && !errorList.isEmpty()) {
statusBlock.setStyle("-fx-background-color: " + ERROR_COLOR);
int rows = model.get().getRows().size();
double space = (double)heightWithoutStatusBlock() / rows;
errorList.forEach(error -> errorMarkerList.add(generateErrorMarker(space, error)));
}
}
getChildren().setAll(errorMarkerList);
}
private int heightWithoutStatusBlock() {
return (int)(getHeight() - STATUS_BLOCK_OFFSET);
}
private Region generateErrorMarker(double space, ValidationError error) {
logger.info("generate error marker for {} errors in line {}", error.getMessages().size(), error.getLineNumber());
logger.info("layout y is set to {}", (space * error.getLineNumber() + STATUS_BLOCK_OFFSET));
Region errorMarker = new Region();
errorMarker.setLayoutY(space * error.getLineNumber() + STATUS_BLOCK_OFFSET);
errorMarker.setPrefSize(WIDTH, 2);
errorMarker.setStyle("-fx-background-color: " + ERROR_COLOR);
errorMarker.setOnMouseClicked(event -> selectedValidationError.setValue(error));
errorMarker.setOnMouseEntered(event -> {
popOver.setContentNode(popupContent(getI18nValidatioMessageWithColumn(resourceBundle, error)));
popOver.show(errorMarker, -16);
});
return errorMarker;
}
private Node popupContent(String text) {
VBox vBox = new VBox();
vBox.setPadding(new Insets(10,10,10,10));
vBox.getChildren().add(new Text(text));
vBox.setAlignment(CENTER);
return vBox;
}
}
@@ -1,113 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import java.util.function.UnaryOperator;
public class GotoLineDialog extends Dialog<Integer> {
private final GridPane grid;
private final Label label;
private final TextField textField;
public GotoLineDialog(int maxLineNumber) {
final DialogPane dialogPane = getDialogPane();
this.textField = new TextField("");
this.textField.setMaxWidth(Double.MAX_VALUE);
UnaryOperator<TextFormatter.Change> filter = change -> {
String text = change.getText();
if (text.matches("[0-9]*")) {
try {
int lineNumber = Integer.parseInt(textField.getText() + text);
if (lineNumber <= maxLineNumber) {
return change;
}
} catch (NumberFormatException e) {
// this happens when focusing textfield or press special keys like DEL
return change;
}
}
return null;
};
TextFormatter<String> textFormatter = new TextFormatter<>(filter);
textField.setTextFormatter(textFormatter);
GridPane.setHgrow(textField, Priority.ALWAYS);
GridPane.setFillWidth(textField, true);
label = createContentLabel(dialogPane.getContentText());
label.setPrefWidth(Region.USE_COMPUTED_SIZE);
label.textProperty().bind(dialogPane.contentTextProperty());
this.grid = new GridPane();
this.grid.setHgap(10);
this.grid.setMaxWidth(Double.MAX_VALUE);
this.grid.setAlignment(Pos.CENTER_LEFT);
dialogPane.contentTextProperty().addListener(o -> updateGrid());
dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
updateGrid();
setResultConverter((dialogButton) -> {
ButtonBar.ButtonData data = dialogButton == null ? null : dialogButton.getButtonData();
return data == ButtonBar.ButtonData.OK_DONE ? Integer.parseInt(textField.getText()) : null;
});
}
private Label createContentLabel(String text) {
Label label = new Label(text);
label.setMaxWidth(Double.MAX_VALUE);
label.setMaxHeight(Double.MAX_VALUE);
label.getStyleClass().add("content");
label.setWrapText(true);
label.setPrefWidth(360);
return label;
}
private void updateGrid() {
grid.getChildren().clear();
grid.add(label, 0, 0);
grid.add(textField, 1, 0);
getDialogPane().setContent(grid);
Platform.runLater(() -> textField.requestFocus());
}
}
@@ -1,133 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
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 ninja.javafx.smartcsv.preferences.Preferences;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ResourceBundle;
import java.util.function.UnaryOperator;
/**
* controller for preferences
*/
@Component
public class PreferencesController extends FXMLController {
@FXML
private TextField quoteChar;
@FXML
private TextField delimiterChar;
@FXML
private CheckBox ignoreEmptyLines;
@FXML
private ComboBox<String> fileEncoding;
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) {
fileEncoding.getItems().addAll(Charset.availableCharsets().keySet());
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(Preferences csvPreference) {
if (csvPreference.quoteChar() != null) {
quoteChar.setText(csvPreference.quoteChar().toString());
} else {
quoteChar.setText("");
}
delimiterChar.setText(Character.toString(csvPreference.delimiterChar()));
ignoreEmptyLines.setSelected(csvPreference.ignoreEmptyLines());
endOfLineSymbols = csvPreference.endOfLineSymbols();
}
public Preferences getCsvPreference() {
var quote = quoteChar.getText().length() == 0 ? null : quoteChar.getText().charAt(0);
return new Preferences(quote, delimiterChar.getText().charAt(0), endOfLineSymbols, ignoreEmptyLines.isSelected());
}
public void setFileEncoding(String fileEncoding) {
this.fileEncoding.setValue(fileEncoding);
}
public String getFileEncoding() {
return fileEncoding.getValue();
}
public boolean getValid() {
return valid.get();
}
public BooleanProperty validProperty() {
return valid;
}
public void setValid(boolean valid) {
this.valid.set(valid);
}
}
@@ -1,141 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.ColorConstants.ERROR_COLOR;
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() {
setText(getItem().getValue());
super.cancelEdit();
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: derive("+ ERROR_COLOR +", 30%)");
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) {
runLater(() -> commitEdit(textField.getValue()));
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
});
}
private static 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;
}
}
}
@@ -1,52 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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();
return row.getColumns().get(key);
}
}
@@ -1,52 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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);
}
}
@@ -1,163 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.RevalidationService;
import ninja.javafx.smartcsv.validation.configuration.ValidationConfiguration;
import ninja.javafx.smartcsv.validation.ValidationError;
import ninja.javafx.smartcsv.validation.Validator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* The CSVModel is the client representation for the csv filepath.
* It holds the data in rows, stores the header and manages the validator.
*/
public final class CSVModel implements ColumnValueProvider {
private static final Logger logger = LogManager.getLogger(CSVModel.class);
private Validator validator;
private ObservableList<CSVRow> rows = FXCollections.observableArrayList();
private String[] header;
private ObservableList<ValidationError> validationError = FXCollections.observableArrayList();
private RevalidationService revalidationService = new RevalidationService();
/**
* sets the validator configuration for the data revalidates
*
* @param validationConfiguration the validator configuration for this data
*/
public void setValidationConfiguration(ValidationConfiguration validationConfiguration) {
this.validator = new Validator(validationConfiguration, this);
revalidate();
}
/**
* returns the data as a list of rows of the
*
* @return list of rows
*/
public ObservableList<CSVRow> getRows() {
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.setRowNumber(rows.size());
rows.add(row);
return row;
}
public void addValue(final CSVRow row, final String column, final String value) {
final CSVValue csvValue = row.addValue(column, value);
csvValue.valueProperty().addListener(observable -> {
if (validator.needsColumnValidation(column)) {
revalidate();
} else {
csvValue.setValidationError(validator.isValid(row.getRowNumber(), column, csvValue.getValue()));
}
});
}
/**
* sets the column headers as string array
*
* @param header the headers of the columns
*/
public void setHeader(String[] header) {
this.header = header;
revalidate();
}
/**
* returns the column headers
*
* @return the column headers
*/
public String[] getHeader() {
return header;
}
public void revalidate(String column) {
if (!hasValidator()) return;
validator.reinitializeColumn(column);
revalidate();
}
/**
* walks through the data and validates each value
*/
public void revalidate() {
validationError.clear();
logger.info("revalidate: hasValidator -> {}", hasValidator());
if (!hasValidator()) return;
revalidationService.setHeader(header);
revalidationService.setRows(rows);
revalidationService.setValidator(validator);
revalidationService.setOnSucceeded(t -> validationError.setAll(revalidationService.getValue()));
revalidationService.setOnFailed(t -> logger.error("revalidation service failed!"));
revalidationService.restart();
}
private boolean hasValidator() {
return validator != null && validator.hasConfig();
}
public ValidationConfiguration createValidationConfiguration() {
ValidationConfiguration newValidationConfiguration = new ValidationConfiguration();
newValidationConfiguration.setHeaderNames(this.header);
this.validator = new Validator(newValidationConfiguration, this);
this.revalidate();
return newValidationConfiguration;
}
@Override
public String getValue(int row, String column) {
return rows.get(row).getColumns().get(column).getValue().getValue();
}
@Override
public int getNumberOfRows() {
return rows.size();
}
}
@@ -1,78 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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;
/**
* This class represents a single row in the csv file.
*/
public class CSVRow {
private ObservableMap<String, ObjectProperty<CSVValue>> columns = FXCollections.observableHashMap();
private int rowNumber;
/**
* 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
*/
CSVValue addValue(String column, String value) {
CSVValue v = new CSVValue();
v.setValue(value);
columns.put(column, new SimpleObjectProperty<>(v));
return v;
}
}
@@ -1,81 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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;
/**
* 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 StringProperty value = new SimpleStringProperty();
private ValidationError valid;
/**
* 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) {
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
*/
public void setValidationError(ValidationError valid) {
this.valid = valid;
}
}
@@ -1,37 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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;
/**
* interface for easier access to values in a column
*/
public interface ColumnValueProvider {
String getValue(int row, String column);
int getNumberOfRows();
}
@@ -1,35 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.util;
/**
* Collection of all the important colors
*/
public class ColorConstants {
public static final String OK_COLOR = "#22aa22";
public static final String ERROR_COLOR = "#ff3333";
}
@@ -1,93 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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, List<ValidationError> errors) {
StringWriter message = new StringWriter();
errors.forEach(error -> message.append(getI18nValidatioMessage(resourceBundle, error)).append("\n"));
if (message.toString().length() != 0) {
return cutOffLastLineBreak(message.toString());
}
return "";
}
public static String getI18nValidatioMessageWithColumn(ResourceBundle resourceBundle, ValidationError error) {
return getI18nValidatioMessage(resourceBundle, error, resourceBundle.getString("column") + " " + error.getColumn() + " : ");
}
public static String getI18nValidatioMessage(ResourceBundle resourceBundle, ValidationError error) {
return getI18nValidatioMessage(resourceBundle, error, "");
}
private static String getI18nValidatioMessage(ResourceBundle resourceBundle, ValidationError error, String prefix) {
List<ValidationMessage> validationMessages = error.getMessages();
StringWriter message = new StringWriter();
validationMessages.forEach(validationMessage -> {
message.append(prefix);
if (resourceBundle.containsKey(validationMessage.getKey())) {
String resourceText = resourceBundle.getString(validationMessage.getKey());
if (validationMessage.getParameters().length > 0) {
message.append(format(resourceText, (Object[]) validationMessage.getParameters())).append("\n");
} else {
message.append(resourceText).append("\n");
}
} else {
message.append(validationMessage.getKey()).append("\n");
}
});
if (!validationMessages.isEmpty()) {
return cutOffLastLineBreak(message.toString());
}
return "";
}
private static String cutOffLastLineBreak(String message) {
return message.substring(0, message.length()-1);
}
}
@@ -1,73 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2021 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.Worker;
import javafx.concurrent.WorkerStateEvent;
import javafx.scene.control.Alert;
import ninja.javafx.smartcsv.fx.SmartCSVController;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* This class helps extract useful messages from exceptions
* TODO: make I18n maybe?
*/
public final class JavaFxUtils {
private static final Logger logger = LogManager.getLogger(SmartCSVController.class);
private JavaFxUtils() {
}
public static void onServiceError(WorkerStateEvent event, String windowTitle, String errorHeader) {
onServiceError(event, windowTitle, errorHeader, () -> {
});
}
public static void onServiceError(WorkerStateEvent event, String windowTitle, String errorHeader, Runnable rollbackAction) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle(windowTitle);
alert.setHeaderText(errorHeader);
alert.setContentText(findExceptionMessage(event.getSource()));
alert.showAndWait();
}
private static String findExceptionMessage(Worker<?> source) {
if (source == null) {
return "Cannot identify the source of the event!";
} else if (source.getException() == null) {
return "The event did not have an exception?";
}
Throwable exception = source.getException();
logger.error("Error in " + source.getClass().getSimpleName(), exception);
if (exception.getMessage() == null) {
return "Exception of type " + exception.getClass() + " had no message, check the logs.";
}
return exception.getMessage();
}
}
@@ -1,57 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.files.FileStorage;
/**
* Service class for async load of a csv file
*/
@org.springframework.stereotype.Service
public class LoadFileService extends Service<Void> {
private FileStorage<?> file;
public void setFileStorage(FileStorage<?> file) {
this.file = file;
}
@Override
protected Task<Void> createTask() {
return new Task<>() {
@Override
protected Void call() throws Exception {
if (file != null) {
file.load();
}
return null;
}
};
}
}
@@ -1,60 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.files.FileStorage;
/**
* Service class for async save of a csv file
*/
@org.springframework.stereotype.Service
public class SaveFileService extends Service<Void> {
private FileStorage<?> file;
public void setFileStorage(FileStorage<?> value) {
file = value;
}
@Override
protected Task<Void> createTask() {
return new Task<>() {
@Override
protected Void call() {
try {
file.save();
} catch (Throwable ex) {
ex.printStackTrace();
}
return null;
}
};
}
}
@@ -1,61 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.validation;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;
import ninja.javafx.smartcsv.validation.configuration.StringFormat;
import java.util.ResourceBundle;
/**
* cell factory for string formats
*/
public class StringFormatEditorCellFactory implements Callback<ListView<StringFormat>, ListCell<StringFormat>> {
private ResourceBundle resourceBundle;
public StringFormatEditorCellFactory(ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
}
@Override
public ListCell<StringFormat> call(ListView<StringFormat> param) {
return new ListCell<StringFormat>(){
@Override
protected void updateItem(StringFormat item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
} else {
setText(resourceBundle.getString("format.type."+item));
}
}
} ;
}
}
@@ -1,54 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.validation;
import javafx.util.StringConverter;
import ninja.javafx.smartcsv.validation.configuration.StringFormat;
import java.util.ResourceBundle;
/**
* converter for string formats
*/
public class StringFormatStringConverter extends StringConverter<StringFormat> {
private ResourceBundle resourceBundle;
public StringFormatStringConverter(ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
}
@Override
public String toString(StringFormat item) {
return resourceBundle.getString("format.type."+item);
}
@Override
public StringFormat fromString(String string) {
return StringFormat.fromExternalValue(string);
}
}
@@ -1,507 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.validation;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.SpinnerValueFactory.IntegerSpinnerValueFactory;
import ninja.javafx.smartcsv.fx.FXMLController;
import ninja.javafx.smartcsv.validation.configuration.*;
import org.fxmisc.richtext.CodeArea;
import org.fxmisc.richtext.LineNumberFactory;
import org.fxmisc.richtext.model.StyleSpans;
import org.fxmisc.richtext.model.StyleSpansBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.lang.Boolean.FALSE;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.joining;
import static javafx.beans.binding.Bindings.when;
import static ninja.javafx.smartcsv.validation.configuration.Type.STRING;
/**
* controller for editing column validations
*
* RichText groovy highlighting code is based on the java example of
* https://github.com/TomasMikula/RichTextFX
*/
@Component
public class ValidationEditorController extends FXMLController {
private StringProperty selectedColumn = new SimpleStringProperty();
private ValidationConfiguration validationConfiguration;
private static final String[] KEYWORDS = new String[] {
"abstract", "assert", "boolean", "break", "byte",
"case", "catch", "char", "class",
"continue", "def", "default", "do", "double", "else",
"enum", "extends", "false", "final", "finally", "float",
"for", "if", "implements", "import", "in",
"instanceof", "int", "interface", "length", "long", "native",
"new", "null", "package", "private", "property", "protected", "public",
"return", "short", "static", "super",
"switch", "synchronized", "this", "threadsafe", "throw", "throws",
"transient", "true", "try", "void", "volatile", "while"
};
private static final String KEYWORD_PATTERN = "\\b(" + String.join("|", (CharSequence[]) KEYWORDS) + ")\\b";
private static final String PAREN_PATTERN = "\\(|\\)";
private static final String BRACE_PATTERN = "\\{|\\}";
private static final String BRACKET_PATTERN = "\\[|\\]";
private static final String SEMICOLON_PATTERN = "\\;";
private static final String STRING_PATTERN = "\"([^\"\\\\]|\\\\.)*\"";
private static final String STRING2_PATTERN = "'([^'\\\\]|\\\\.)*'";
private static final String COMMENT_PATTERN = "//[^\n]*" + "|" + "/\\*(.|\\R)*?\\*/";
private static final Pattern PATTERN = Pattern.compile(
"(?<KEYWORD>" + KEYWORD_PATTERN + ")"
+ "|(?<PAREN>" + PAREN_PATTERN + ")"
+ "|(?<BRACE>" + BRACE_PATTERN + ")"
+ "|(?<BRACKET>" + BRACKET_PATTERN + ")"
+ "|(?<SEMICOLON>" + SEMICOLON_PATTERN + ")"
+ "|(?<STRING>" + STRING_PATTERN + ")"
+ "|(?<STRING2>" + STRING2_PATTERN + ")"
+ "|(?<COMMENT>" + COMMENT_PATTERN + ")"
);
@FXML
private ComboBox<Type> typeComboBox;
@FXML
private ComboBox<StringFormat> formatComboBox;
@FXML
private TextField formatTextField;
@FXML
private Spinner<Integer> minLengthSpinner;
@FXML
private Spinner<Integer> maxLengthSpinner;
@FXML
private TextField regexpRuleTextField;
@FXML
private TextField valueOfRuleTextField;
@FXML
private CodeArea groovyRuleTextArea;
@FXML
private CheckBox enableNotEmptyRule;
@FXML
private CheckBox enableMinLengthRule;
@FXML
private CheckBox enableMaxLengthRule;
@FXML
private CheckBox enableRegexpRule;
@FXML
private CheckBox enableValueOfRule;
@FXML
private CheckBox enableGroovyRule;
@FXML
private CheckBox enableUniqueRule;
@Value("${fxml.smartcvs.validation.editor.view}")
@Override
public void setFxmlFilePath(String filePath) {
this.fxmlFilePath = filePath;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
initTypeAndFormatInput(resources);
initMinMaxSpinner();
initSpinner(minLengthSpinner, enableMinLengthRule);
initSpinner(maxLengthSpinner, enableMaxLengthRule);
initTextInputControl(regexpRuleTextField, enableRegexpRule);
initTextInputControl(valueOfRuleTextField, enableValueOfRule);
initCodeAreaControl(groovyRuleTextArea, enableGroovyRule);
}
public String getSelectedColumn() {
return selectedColumn.get();
}
public StringProperty selectedColumnProperty() {
return selectedColumn;
}
public void setSelectedColumn(String selectedColumn) {
this.selectedColumn.set(selectedColumn);
}
public void setValidationConfiguration(ValidationConfiguration validationConfiguration) {
this.validationConfiguration = validationConfiguration;
}
private void initTypeAndFormatInput(ResourceBundle resources) {
typeComboBox.getItems().addAll(STRING,
Type.INTEGER,
Type.NUMBER,
Type.DATE,
Type.DATETIME,
Type.TIME);
formatComboBox.setCellFactory(new StringFormatEditorCellFactory(resources));
formatComboBox.setConverter(new StringFormatStringConverter(resources));
formatComboBox.getItems().addAll(
StringFormat.DEFAULT,
StringFormat.EMAIL,
StringFormat.URI,
StringFormat.BINARY,
StringFormat.UUID
);
typeComboBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> changeFormat());
}
private void updateFormatTextField() {
switch (typeComboBox.getValue()) {
case DATE:
case DATETIME:
case TIME:
formatTextField.setVisible(true);
formatTextField.setText(getCurrentFieldConfig().getFormat());
break;
default:
formatTextField.setVisible(false);
formatTextField.setText(null);
break;
}
}
private void updateFormatComboBox() {
switch (typeComboBox.getValue()) {
case STRING:
formatComboBox.setVisible(true);
formatComboBox.getSelectionModel().select(StringFormat.fromExternalValue(getCurrentFieldConfig().getFormat()));
break;
default:
formatComboBox.setVisible(false);
break;
}
}
private void initMinMaxSpinner() {
IntegerSpinnerValueFactory minValueFactory = new IntegerSpinnerValueFactory(0, Integer.MAX_VALUE, 0);
minLengthSpinner.setValueFactory(minValueFactory);
IntegerSpinnerValueFactory maxValueFactory = new IntegerSpinnerValueFactory(0, Integer.MAX_VALUE, 0);
maxLengthSpinner.setValueFactory(maxValueFactory);
minValueFactory.maxProperty().bind(
when(enableMaxLengthRule.selectedProperty()).
then(maxLengthSpinner.valueProperty()).
otherwise(Integer.MAX_VALUE));
maxValueFactory.minProperty().bind(
when(enableMinLengthRule.selectedProperty()).
then(minLengthSpinner.valueProperty()).
otherwise(0));
}
private void changeFormat() {
switch (typeComboBox.getValue()) {
case STRING:
updateFormatComboBox();
break;
case DATE:
case DATETIME:
case TIME:
updateFormatTextField();
break;
case INTEGER:
case NUMBER:
default:
// format: no options
formatComboBox.setVisible(false);
formatTextField.setVisible(false);
break;
}
}
public void updateConfiguration() {
Field config = getCurrentFieldConfig();
config.setType(typeComboBox.getValue());
switch (typeComboBox.getValue()) {
case STRING:
config.setFormat(formatComboBox.getValue().getExternalValue());
break;
case DATE:
case DATETIME:
case TIME:
if (formatTextField.getText().trim().isEmpty()) {
config.setFormat(null);
} else {
// TODO: validate input
config.setFormat(formatTextField.getText());
}
break;
case INTEGER:
case NUMBER:
default:
// format: no options
config.setFormat(null);
break;
}
if (enableGroovyRule.isSelected()) {
config.setGroovy(groovyRuleTextArea.getText());
} else {
config.setGroovy(null);
}
Constraints constraints = config.getConstraints();
if (constraints == null) {
constraints = new Constraints();
config.setConstraints(constraints);
}
if (enableNotEmptyRule.isSelected()) {
constraints.setRequired(enableNotEmptyRule.isSelected());
} else {
constraints.setRequired(null);
}
if (enableUniqueRule.isSelected()) {
constraints.setUnique(enableUniqueRule.isSelected());
} else {
constraints.setUnique(null);
}
if (enableMinLengthRule.isSelected()) {
constraints.setMinLength(minLengthSpinner.getValue());
} else {
constraints.setMinLength(null);
}
if (enableMaxLengthRule.isSelected()) {
constraints.setMaxLength(maxLengthSpinner.getValue());
} else {
constraints.setMaxLength(null);
}
if (enableRegexpRule.isSelected()) {
constraints.setPattern(regexpRuleTextField.getText());
} else {
constraints.setPattern(null);
}
if (enableValueOfRule.isSelected()) {
constraints.setEnumeration(asList(valueOfRuleTextField.getText().split(", ")));
} else {
constraints.setEnumeration(null);
}
}
private Field getCurrentFieldConfig() {
return validationConfiguration.getFieldConfiguration(getSelectedColumn());
}
private void addDependencyListener(CheckBox rule, CheckBox... dependentRules) {
rule.selectedProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) {
for (CheckBox dependentRule: dependentRules) {
dependentRule.selectedProperty().setValue(false);
}
}
});
}
public void updateForm() {
Field config = getCurrentFieldConfig();
if (config.getType() != null) {
typeComboBox.setValue(config.getType());
} else {
typeComboBox.setValue(STRING);
}
updateFormatComboBox();
updateFormatTextField();
updateCodeAreaControl(
groovyRuleTextArea,
config.getGroovy(),
enableGroovyRule
);
Constraints constraints = config.getConstraints();
updateCheckBox(constraints != null ? constraints.getRequired() : FALSE, enableNotEmptyRule);
updateCheckBox(constraints != null ? constraints.getUnique() : FALSE, enableUniqueRule);
updateSpinner(
minLengthSpinner,
constraints != null ? constraints.getMinLength() : null,
enableMinLengthRule
);
updateSpinner(
maxLengthSpinner,
constraints != null ? constraints.getMaxLength() : null,
enableMaxLengthRule
);
updateTextInputControl(
regexpRuleTextField,
constraints != null ? constraints.getPattern() : null,
enableRegexpRule
);
updateTextInputControl(
valueOfRuleTextField,
constraints != null ? constraints.getEnumeration() : null,
enableValueOfRule
);
}
private void updateCheckBox(Boolean value, CheckBox ruleEnabled) {
if (value == null) {
ruleEnabled.setSelected(false);
} else {
ruleEnabled.setSelected(value);
}
}
private void updateSpinner(Spinner rule, Integer value, CheckBox ruleEnabled) {
if (value == null) {
ruleEnabled.setSelected(false);
} else {
ruleEnabled.setSelected(true);
rule.getValueFactory().setValue(value);
}
}
private void updateTextInputControl(TextInputControl rule, String value, CheckBox ruleEnabled) {
if (value == null) {
ruleEnabled.setSelected(false);
} else {
ruleEnabled.setSelected(true);
rule.setText(value);
}
}
private void updateTextInputControl(TextInputControl rule, List<String> values, CheckBox ruleEnabled) {
if (values == null || values.isEmpty()) {
ruleEnabled.setSelected(false);
} else {
ruleEnabled.setSelected(true);
rule.setText(values.stream().collect(joining(", ")));
}
}
private void updateCodeAreaControl(CodeArea rule, String value, CheckBox ruleEnabled) {
if (value == null) {
ruleEnabled.setSelected(false);
} else {
ruleEnabled.setSelected(true);
rule.replaceText(0, rule.getLength(), value);
}
}
private void initSpinner(Spinner rule, CheckBox ruleEnabled) {
rule.disableProperty().bind(ruleEnabled.selectedProperty().not());
ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
rule.getValueFactory().setValue(0);
}
});
}
private void initTextInputControl(TextInputControl rule, CheckBox ruleEnabled) {
rule.disableProperty().bind(ruleEnabled.selectedProperty().not());
ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
rule.setText("");
}
});
}
private void initCodeAreaControl(CodeArea rule, CheckBox ruleEnabled) {
rule.disableProperty().bind(ruleEnabled.selectedProperty().not());
ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
rule.clear();
}
});
rule.setParagraphGraphicFactory(LineNumberFactory.get(rule));
rule.richChanges()
.filter(ch -> !ch.getInserted().equals(ch.getRemoved())) // XXX
.subscribe(change -> {
rule.setStyleSpans(0, computeHighlighting(rule.getText()));
});
}
private static StyleSpans<Collection<String>> computeHighlighting(String text) {
Matcher matcher = PATTERN.matcher(text);
int lastKwEnd = 0;
StyleSpansBuilder<Collection<String>> spansBuilder
= new StyleSpansBuilder<>();
while(matcher.find()) {
String styleClass =
matcher.group("KEYWORD") != null ? "keyword" :
matcher.group("PAREN") != null ? "paren" :
matcher.group("BRACE") != null ? "brace" :
matcher.group("BRACKET") != null ? "bracket" :
matcher.group("SEMICOLON") != null ? "semicolon" :
matcher.group("STRING") != null ? "string" :
matcher.group("STRING2") != null ? "string" :
matcher.group("COMMENT") != null ? "comment" :
null; /* never happens */ assert styleClass != null;
spansBuilder.add(Collections.emptyList(), matcher.start() - lastKwEnd);
spansBuilder.add(Collections.singleton(styleClass), matcher.end() - matcher.start());
lastKwEnd = matcher.end();
}
spansBuilder.add(Collections.emptyList(), text.length() - lastKwEnd);
return spansBuilder.create();
}
}
@@ -1,44 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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 java.nio.charset.Charset;
/**
* Helper class for getting charset's name
*/
public class CharsetHelper {
public static String getCharsetName(String name) {
try {
return Charset.forName(name).name();
} catch (Exception e) {
return Charset.defaultCharset().name();
}
}
}
@@ -1,62 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileReader;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
/**
* file reader for the file encoding
*/
public class EncodingFileReader implements FileReader<String> {
private String fileEncoding;
public EncodingFileReader() {
fileEncoding = Charset.defaultCharset().name();
}
@Override
public String getContent() {
return fileEncoding;
}
@Override
public void read(File filename) throws IOException {
Map settings = new GsonBuilder().create().fromJson(new java.io.FileReader(filename), HashMap.class);
if (settings != null) {
fileEncoding = CharsetHelper.getCharsetName(settings.get("fileEncoding").toString());
}
}
}
@@ -1,59 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.google.gson.Gson;
import com.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileWriter;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
/**
* Save the file encoding to configuration file
*/
public class EncodingFileWriter implements FileWriter<String> {
private String fileEncoding;
@Override
public void setContent(String fileEncoding) {
this.fileEncoding = fileEncoding;
}
@Override
public void write(File filename) throws IOException {
Map<String, String> encodings = new HashMap<>();
encodings.put("fileEncoding", CharsetHelper.getCharsetName(fileEncoding));
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Files.write(filename.toPath(), gson.toJson(encodings).getBytes());
}
}
@@ -1,38 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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;
public record Preferences(
Character quoteChar,
char delimiterChar,
String endOfLineSymbols,
boolean ignoreEmptyLines) {
public static Preferences defaultPreferences() {
return new Preferences('\"',',', "\n", true);
}
}
@@ -1,68 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileReader;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static ninja.javafx.smartcsv.preferences.Preferences.defaultPreferences;
/**
* file reader for the preferences
*/
public class PreferencesFileReader implements FileReader<Preferences> {
private Preferences csvPreference;
public PreferencesFileReader() {
csvPreference = defaultPreferences();
}
@Override
public void read(File filename) throws IOException {
Map config = new GsonBuilder().create().fromJson(new java.io.FileReader(filename), HashMap.class);
if (config != null) {
Character quoteChar = config.get("quoteChar") == null ? null : config.get("quoteChar").toString().charAt(0);
char delimiterChar = config.get("delimiterChar").toString().charAt(0);
String endOfLineSymbols = config.get("endOfLineSymbols").toString();
boolean ignoreEmptyLines = (Boolean) config.get("ignoreEmptyLines");
csvPreference = new Preferences(quoteChar, delimiterChar, endOfLineSymbols, ignoreEmptyLines);
}
}
public Preferences getContent() {
return csvPreference;
}
}
@@ -1,61 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.google.gson.Gson;
import com.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileWriter;
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
*/
public class PreferencesFileWriter implements FileWriter<Preferences> {
private Preferences csvPreference;
public void setContent(Preferences csvPreference) {
this.csvPreference = csvPreference;
}
public void write(File file) throws IOException {
Map<String, Object> preferences = new HashMap<>();
preferences.put("quoteChar", csvPreference.quoteChar() == null ? null: csvPreference.quoteChar().toString());
preferences.put("delimiterChar", Character.toString((char)csvPreference.delimiterChar()));
preferences.put("endOfLineSymbols", csvPreference.endOfLineSymbols());
preferences.put("ignoreEmptyLines", csvPreference.ignoreEmptyLines());
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Files.write(file.toPath(), gson.toJson(preferences).getBytes());
}
}
@@ -1,110 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import javafx.beans.property.ObjectProperty;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Service for running the validation async of the ui thread
*/
public class RevalidationService extends Service<List<ValidationError>> {
private static final Logger logger = LogManager.getLogger(RevalidationService.class);
private Validator validator;
private List<CSVRow> rows;
private String[] header;
public void setValidator(Validator validator) {
this.validator = validator;
}
public void setRows(List<CSVRow> rows) {
this.rows = rows;
}
public void setHeader(String[] header) {
this.header = header;
}
@Override
protected Task<List<ValidationError>> createTask() {
return new Task<List<ValidationError>>() {
@Override
protected List<ValidationError> call() throws Exception {
List<ValidationError> errors = new ArrayList<>();
try {
if (header != null) {
ValidationError headerError = validator.isHeaderValid(header);
if (headerError != null) {
logger.info("revalidate: header error found");
errors.add(headerError);
}
}
int maxRows = rows.size();
for (int lineNumber = 0; lineNumber < maxRows; lineNumber++) {
CSVRow row = rows.get(lineNumber);
Map<String, ObjectProperty<CSVValue>> table = row.getColumns();
Set<String> columns = table.keySet();
for (String column : columns) {
CSVValue value = table.get(column).getValue();
if (validator != null) {
ValidationError validationError = validator.isValid(lineNumber, column, value.getValue());
if (validationError != null) {
logger.info("revalidate: {} errors found in line {}", validationError.getMessages().size(), lineNumber);
errors.add(validationError);
value.setValidationError(validationError);
} else {
value.setValidationError(null);
}
} else {
value.setValidationError(null);
}
}
}
} catch (Throwable t) {
logger.error("validation error", t);
}
return errors;
}
};
}
}
@@ -1,80 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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 String column = "";
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 ValidationError column(String column) {
this.column = column;
return this;
}
public Integer getLineNumber() {
return lineNumber;
}
public String getColumn() {
return column;
}
public List<ValidationMessage> getMessages() {
return messages;
}
public ValidationError add(String key, String... parameters) {
messages.add(new ValidationMessage(key, parameters));
return this;
}
public boolean isEmpty() {
return messages.isEmpty();
}
}
@@ -1,78 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import com.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileReader;
import ninja.javafx.smartcsv.validation.configuration.Field;
import ninja.javafx.smartcsv.validation.configuration.ValidationConfiguration;
import java.io.File;
import java.io.IOException;
import static ninja.javafx.smartcsv.validation.configuration.Type.*;
/**
* This class loads the constraints as json config
*/
public class ValidationFileReader implements FileReader<ValidationConfiguration> {
private ValidationConfiguration config;
@Override
public void read(File file) throws IOException {
config = new GsonBuilder().create().fromJson(new java.io.FileReader(file), ValidationConfiguration.class);
setDefaults();
}
private void setDefaults() {
for (Field field : config.getFields()) {
if (field.getType() == null) {
field.setType(STRING);
}
if (field.getType() == DATE) {
if (field.getFormat() == null) {
field.setFormat("yyyy-MM-dd");
}
}
if (field.getType() == DATETIME) {
if (field.getFormat() == null) {
field.setFormat("yyyy-MM-ddThh:mm:ssZ");
}
}
if (field.getType() == TIME) {
if (field.getFormat() == null) {
field.setFormat("hh:mm:ss");
}
}
}
}
public ValidationConfiguration getContent() {
return config;
}
}
@@ -1,54 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileWriter;
import ninja.javafx.smartcsv.validation.configuration.ValidationConfiguration;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
/**
* file writer for the validation configuration
*/
public class ValidationFileWriter implements FileWriter<ValidationConfiguration> {
private ValidationConfiguration validationConfiguration;
public void setContent(ValidationConfiguration validationConfiguration) {
this.validationConfiguration = validationConfiguration;
}
@Override
public void write(File file) throws IOException {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Files.write(file.toPath(), gson.toJson(validationConfiguration).getBytes());
}
}
@@ -1,52 +0,0 @@
package ninja.javafx.smartcsv.validation;
import java.text.SimpleDateFormat;
/**
* @author abi
*/
public class ValidationFormatHelper {
public static String dateFormat(String format, String defaultFormat) {
if (format != null && !format.trim().isEmpty()) {
format = format.trim();
if (format.startsWith("fmt:")) {
format = format.substring(4);
format = format.replace("%Y", "yyyy");
format = format.replace("%y", "yy");
format = format.replace("%m", "MM");
format = format.replace("%d", "dd");
format = format.replace("%a", "E");
format = format.replace("%A", "EEEE");
format = format.replace("%w", "F");
format = format.replace("%b", "MMM");
format = format.replace("%B", "MMMMM");
format = format.replace("%H", "HH");
format = format.replace("%I", "hh");
format = format.replace("%p", "a");
format = format.replace("%M", "mm");
format = format.replace("%S", "ss");
format = format.replace("%z", "Z");
format = format.replace("%Z", "z");
format = format.replace("%j", "DDD");
format = format.replace("%U", "ww");
return format;
} else {
try {
new SimpleDateFormat(format);
return format;
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
return defaultFormat;
}
public static Integer doubleToInteger(Double value) {
if (value == null) return null;
return (int)Math.round(value);
}
}
@@ -1,79 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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) +
'}';
}
}
@@ -1,296 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import ninja.javafx.smartcsv.fx.table.model.ColumnValueProvider;
import ninja.javafx.smartcsv.validation.checker.*;
import ninja.javafx.smartcsv.validation.configuration.Constraints;
import ninja.javafx.smartcsv.validation.configuration.Field;
import ninja.javafx.smartcsv.validation.configuration.ValidationConfiguration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static ninja.javafx.smartcsv.validation.ValidationFormatHelper.dateFormat;
import static ninja.javafx.smartcsv.validation.configuration.StringFormat.*;
import static ninja.javafx.smartcsv.validation.configuration.Type.*;
/**
* This class checks all the validations defined in the
* Config against a given value
*/
public class Validator {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// member variables
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private ValidationConfiguration validationConfig;
private ColumnValueProvider columnValueProvider;
private Map<String, Map<Validation.Type, Validation>> columnValidationMap = new HashMap<>();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constructors
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* JSON configuration for this validator
*
* @param validationConfig
*/
public Validator(ValidationConfiguration validationConfig, ColumnValueProvider columnValueProvider) {
this.validationConfig = validationConfig;
this.columnValueProvider = columnValueProvider;
initColumnValidations();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public boolean needsColumnValidation(String column) {
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap != null) {
return validationMap.containsKey(Validation.Type.UNIQUE);
}
return false;
}
/**
* checks if the value is valid for the column configuration
*
* @param column the column name
* @param value the value to check
* @return ValidationError with information if valid and if not which getMessage happened
*/
public ValidationError isValid(Integer row, String column, String value) {
ValidationError result = null;
if (hasConfig()) {
ValidationError error = ValidationError.withLineNumber(row).column(column);
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap != null) {
for (Validation validation: validationMap.values()) {
if (validation.canBeChecked(value)) {
validation.check(row, value, error);
}
}
}
if (!error.isEmpty()) {
result = error;
}
}
return result;
}
public boolean hasConfig() {
return validationConfig != null;
}
public void reinitializeColumn(String column) {
clear(column);
initializeColumnWithRules(column);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void add(String column, Validation validation) {
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap == null) {
validationMap = new HashMap<>();
columnValidationMap.put(column, validationMap);
}
validationMap.put(validation.getType(), validation);
}
private void remove(String column, Validation.Type type) {
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap == null) {
validationMap = new HashMap<>();
columnValidationMap.put(column, validationMap);
}
validationMap.remove(type);
}
private void clear(String column) {
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap != null) {
validationMap.clear();
}
}
private void initColumnValidations() {
if (hasConfig()) {
for (Field column : validationConfig.getFields()) {
initializeColumnWithRules(column);
}
}
}
private void initializeColumnWithRules(String columnName) {
if (hasConfig()) {
for (Field column : validationConfig.getFields()) {
if (column.getName().equals(columnName)) {
initializeColumnWithRules(column);
break;
}
}
}
}
private void initializeColumnWithRules(Field column) {
if (column.getType() != null) {
if (column.getType() == NUMBER) {
add(column.getName(), new DoubleValidation());
}
if (column.getType() == INTEGER) {
add(column.getName(), new IntegerValidation());
}
if (column.getType() == DATE) {
String format = dateFormat(column.getFormat(), "yyyy-MM-dd");
add(column.getName(), new DateValidation(format));
}
if (column.getType() == DATETIME) {
String format = dateFormat(column.getFormat(), "yyyy-MM-ddThh:mm:ssZ");
add(column.getName(), new DateValidation(format));
}
if (column.getType() == TIME) {
String format = dateFormat(column.getFormat(), "hh:mm:ss");
add(column.getName(), new DateValidation(format));
}
if (column.getType() == STRING && column.getFormat() == null) {
remove(column.getName(), Validation.Type.STRING);
} else {
if (column.getType() == STRING && column.getFormat().equalsIgnoreCase(EMAIL.getExternalValue())) {
add(column.getName(), new EmailValidation());
}
if (column.getType() == STRING && column.getFormat().equalsIgnoreCase(URI.getExternalValue())) {
add(column.getName(), new UriValidation());
}
if (column.getType() == STRING && column.getFormat().equalsIgnoreCase(UUID.getExternalValue())) {
add(column.getName(), new UuidValidation());
}
if (column.getType() == STRING && column.getFormat().equalsIgnoreCase(BINARY.getExternalValue())) {
add(column.getName(), new BinaryValidation());
}
}
}
String groovy = column.getGroovy();
if (groovy != null && !groovy.trim().isEmpty()) {
add(column.getName(), new GroovyValidation(groovy));
}
Constraints constraints = column.getConstraints();
if (constraints != null) {
Boolean notEmptyRule = constraints.getRequired();
if (notEmptyRule != null && notEmptyRule) {
add(column.getName(), new NotEmptyValidation());
}
Boolean uniqueRule = constraints.getUnique();
if (uniqueRule != null && uniqueRule) {
add(column.getName(), new UniqueValidation(columnValueProvider, column.getName()));
}
Integer minLength = constraints.getMinLength();
if (minLength != null) {
add(column.getName(), new MinLengthValidation(minLength));
}
Integer maxLength = constraints.getMaxLength();
if (maxLength != null) {
add(column.getName(), new MaxLengthValidation(maxLength));
}
String regexp = constraints.getPattern();
if (regexp != null && !regexp.trim().isEmpty()) {
add(column.getName(), new RegExpValidation(regexp));
}
List<String> valueOfRule = constraints.getEnumeration();
if (valueOfRule != null && !valueOfRule.isEmpty()) {
add(column.getName(), new ValueOfValidation(valueOfRule));
}
}
}
public ValidationError isHeaderValid(String[] headerNames) {
ValidationError result = null;
if (validationConfig != null) {
String[] headerNamesConfig = validationConfig.headerNames();
if (headerNamesConfig != null) {
if (headerNames.length != headerNamesConfig.length) {
result = ValidationError.withoutLineNumber().add("validation.message.header.length",
Integer.toString(headerNames.length),
Integer.toString(headerNamesConfig.length));
return result;
}
ValidationError error = ValidationError.withoutLineNumber();
for (int i = 0; i < headerNamesConfig.length; i++) {
if (!headerNamesConfig[i].equals(headerNames[i])) {
error.add("validation.message.header.match",
Integer.toString(i),
headerNamesConfig[i],
headerNames[i]);
}
}
if (!error.isEmpty()) {
result = error;
}
}
}
return result;
}
}
@@ -1,50 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.validation.ValidationError;
import java.util.Base64;
/**
* checks if the value is a base64 encoded string representing binary data
*/
public class BinaryValidation extends EmptyValueIsValid {
@Override
public void check(int row, String value, ValidationError error) {
try {
Base64.getDecoder().decode(value);
} catch (IllegalArgumentException e) {
error.add("validation.message.binary");
}
}
@Override
public Type getType() {
return Type.STRING;
}
}
@@ -1,55 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.validation.ValidationError;
import static org.apache.commons.validator.GenericValidator.isDate;
/**
* Checks if the date has the right format
*/
public class DateValidation extends EmptyValueIsValid {
private String dateformat;
public DateValidation(String dateformat) {
assert dateformat != null && !dateformat.trim().isEmpty() : "empty date format for date validation";
this.dateformat = dateformat;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!isDate(value, dateformat, true)) {
error.add("validation.message.date.format", dateformat);
}
}
@Override
public Type getType() {
return Type.DATE;
}
}
@@ -1,48 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.validation.ValidationError;
import static org.apache.commons.validator.GenericValidator.isDouble;
/**
* Checks if the value is a double
*/
public class DoubleValidation extends EmptyValueIsValid {
@Override
public void check(int row, String value, ValidationError error) {
if (!isDouble(value)) {
error.add("validation.message.double");
}
}
@Override
public Type getType() {
return Type.DOUBLE;
}
}
@@ -1,47 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.validation.ValidationError;
import org.apache.commons.validator.routines.EmailValidator;
/**
* checks if the value is a valid email address
*/
public class EmailValidation extends EmptyValueIsValid {
@Override
public void check(int row, String value, ValidationError error) {
if (!EmailValidator.getInstance().isValid(value)) {
error.add("validation.message.email");
}
}
@Override
public Type getType() {
return Type.STRING;
}
}
@@ -1,12 +0,0 @@
package ninja.javafx.smartcsv.validation.checker;
/**
* validations based on this are not validated when the value is null or empty
*/
public abstract class EmptyValueIsValid implements Validation {
@Override
public boolean canBeChecked(String value) {
return value != null && !value.isEmpty();
}
}
@@ -1,79 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import ninja.javafx.smartcsv.validation.ValidationError;
import org.codehaus.groovy.control.CompilationFailedException;
/**
* Executes the given groovy as check
*/
public class GroovyValidation extends EmptyValueIsValid {
private String groovyScript;
private Script script;
public GroovyValidation(String groovyScript) {
this.groovyScript = groovyScript;
GroovyShell shell = new GroovyShell();
script = shell.parse(groovyScript);
}
@Override
public void check(int row, String value, ValidationError error) {
Binding binding = new Binding();
binding.setVariable("value", value);
script.setBinding(binding);
Object groovyResult = null;
try {
groovyResult = script.run();
} catch (CompilationFailedException e) {
error.add("validation.message.groovy.exception", groovyScript, e.getMessage());
e.printStackTrace();
}
if (groovyResult == null) {
error.add("validation.message.groovy.return.null", groovyScript);
}
if (!isScriptResultTrue(groovyResult)) {
error.add(groovyResult.toString());
}
}
@Override
public Type getType() {
return Type.GROOVY;
}
private boolean isScriptResultTrue(Object groovyResult) {
return groovyResult.equals(true) || groovyResult.toString().trim().toLowerCase().equals("true");
}
}
@@ -1,48 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.validation.ValidationError;
import static org.apache.commons.validator.GenericValidator.isInt;
/**
* Checks if the value is an integer
*/
public class IntegerValidation extends EmptyValueIsValid {
@Override
public void check(int row, String value, ValidationError error) {
if (!isInt(value)) {
error.add("validation.message.integer");
}
}
@Override
public Type getType() {
return Type.INTEGER;
}
}
@@ -1,54 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.validation.ValidationError;
import static org.apache.commons.validator.GenericValidator.maxLength;
/**
* Checks if the value is shorter or exactly as long as the given max length
*/
public class MaxLengthValidation extends EmptyValueIsValid {
private int maxLength;
public MaxLengthValidation(int maxLength) {
this.maxLength = maxLength;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!maxLength(value, maxLength)) {
error.add("validation.message.max.length", Integer.toString(maxLength));
}
}
@Override
public Type getType() {
return Type.MAX_LENGTH;
}
}
@@ -1,54 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.validation.ValidationError;
import static org.apache.commons.validator.GenericValidator.minLength;
/**
* Checks if the value is at minimum long as the given min length
*/
public class MinLengthValidation extends EmptyValueIsValid {
private int minLength;
public MinLengthValidation(int minLength) {
this.minLength = minLength;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!minLength(value, minLength)) {
error.add("validation.message.min.length", Integer.toString(minLength));
}
}
@Override
public Type getType() {
return Type.MIN_LENGTH;
}
}
@@ -1,53 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.validation.ValidationError;
import static org.apache.commons.validator.GenericValidator.isBlankOrNull;
/**
* Checks if the value is not empty
*/
public class NotEmptyValidation implements Validation {
@Override
public void check(int row, String value, ValidationError error) {
if (isBlankOrNull(value)) {
error.add("validation.message.not.empty");
}
}
@Override
public Type getType() {
return Type.NOT_EMPTY;
}
@Override
public boolean canBeChecked(String value) {
return true;
}
}
@@ -1,54 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.validation.ValidationError;
import static org.apache.commons.validator.GenericValidator.matchRegexp;
/**
* Checks the value against the given reg exp
*/
public class RegExpValidation extends EmptyValueIsValid {
private String regexp;
public RegExpValidation(String regexp) {
this.regexp = regexp;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!matchRegexp(value, regexp)) {
error.add("validation.message.regexp", regexp);
}
}
@Override
public Type getType() {
return Type.REGEXP;
}
}
@@ -1,79 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.fx.table.model.ColumnValueProvider;
import ninja.javafx.smartcsv.validation.ValidationError;
import java.util.ArrayList;
import java.util.List;
import static java.util.Collections.sort;
import static java.util.stream.Collectors.joining;
/**
* Checks if the value is unique in the column
*/
public class UniqueValidation extends EmptyValueIsValid {
private ColumnValueProvider columnValueProvider;
private String column;
public UniqueValidation(ColumnValueProvider columnValueProvider, String column) {
this.columnValueProvider = columnValueProvider;
this.column = column;
}
@Override
public void check(int row, String value, ValidationError error) {
List<Integer> lineNumbers = new ArrayList<>();
int numberOfRows = columnValueProvider.getNumberOfRows();
for (int currentRowOfIteration = 0; currentRowOfIteration < numberOfRows; currentRowOfIteration++) {
String storedValue = columnValueProvider.getValue(currentRowOfIteration, column);
if (value.equals(storedValue) && currentRowOfIteration != row) {
lineNumbers.add(currentRowOfIteration + 1); // show not 0 based line numbers to user
}
}
if (!lineNumbers.isEmpty()) {
if (lineNumbers.size() > 1) {
sort(lineNumbers);
error.add("validation.message.uniqueness.multiple", value, lineNumbers.stream().map(Object::toString).collect(joining(", ")));
} else {
error.add("validation.message.uniqueness.single", value, lineNumbers.get(0).toString());
}
}
}
@Override
public Type getType() {
return Type.UNIQUE;
}
}
@@ -1,51 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.validation.ValidationError;
import java.net.URI;
import java.net.URISyntaxException;
/**
* checks if the value is a valid uri address
*/
public class UriValidation extends EmptyValueIsValid {
@Override
public void check(int row, String value, ValidationError error) {
try {
new URI(value);
} catch (URISyntaxException e) {
error.add("validation.message.uri");
}
}
@Override
public Type getType() {
return Type.STRING;
}
}
@@ -1,51 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.validation.ValidationError;
import java.util.UUID;
/**
* checks if the value is a valid uuid
*/
public class UuidValidation extends EmptyValueIsValid {
@SuppressWarnings("ResultOfMethodCallIgnored")
@Override
public void check(int row, String value, ValidationError error) {
try {
UUID.fromString(value);
} catch (IllegalArgumentException e) {
error.add("validation.message.uuid");
}
}
@Override
public Type getType() {
return Type.STRING;
}
}
@@ -1,39 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.validation.ValidationError;
/**
* Interface for all validations
*/
public interface Validation {
enum Type { NOT_EMPTY, UNIQUE, DOUBLE, INTEGER, MIN_LENGTH, MAX_LENGTH, DATE, REGEXP, VALUE_OF, STRING, GROOVY }
void check(int row, String value, ValidationError error);
Type getType();
boolean canBeChecked(String value);
}
@@ -1,57 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.checker;
import ninja.javafx.smartcsv.validation.ValidationError;
import java.util.List;
import static java.util.stream.Collectors.joining;
/**
* Checks if the value is part of a list of values
*/
public class ValueOfValidation extends EmptyValueIsValid {
private List<String> values;
public ValueOfValidation(List<String> values) {
this.values = values;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!values.contains(value)) {
String commaSeparated = values.stream().collect(joining(", "));
error.add("validation.message.value.of", value, commaSeparated);
}
}
@Override
public Type getType() {
return Type.VALUE_OF;
}
}
@@ -1,96 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.configuration;
import com.google.gson.annotations.SerializedName;
import java.util.List;
/**
* contraints defined in JSON Table Schema
* @see <a href="http://specs.frictionlessdata.io/json-table-schema/">JSON Table Schema</a>
*/
public class Constraints {
private Boolean required;
private Boolean unique;
private Integer minLength;
private Integer maxLength;
private String pattern;
@SerializedName("enum")
private List<String> enumeration;
public Boolean getRequired() {
return required;
}
public void setRequired(Boolean required) {
this.required = required;
}
public Boolean getUnique() {
return unique;
}
public void setUnique(Boolean unique) {
this.unique = unique;
}
public Integer getMinLength() {
return minLength;
}
public void setMinLength(Integer minLength) {
this.minLength = minLength;
}
public Integer getMaxLength() {
return maxLength;
}
public void setMaxLength(Integer maxLength) {
this.maxLength = maxLength;
}
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
public List<String> getEnumeration() {
return enumeration;
}
public void setEnumeration(List<String> enumeration) {
this.enumeration = enumeration;
}
}
@@ -1,109 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.configuration;
/**
* this class represents a field in the configuration
* @see <a href="http://specs.frictionlessdata.io/json-table-schema/">JSON Table Schema</a>
*/
public class Field {
private String name;
private String title;
private Type type;
private String description;
private String format;
private Object missingValue;
private Constraints constraints;
private String groovy;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
public Object getMissingValue() {
return missingValue;
}
public void setMissingValue(Object missingValue) {
this.missingValue = missingValue;
}
public Constraints getConstraints() {
return constraints;
}
public void setConstraints(Constraints constraints) {
this.constraints = constraints;
}
public String getGroovy() {
return groovy;
}
public void setGroovy(String groovy) {
this.groovy = groovy;
}
}
@@ -1,60 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.configuration;
/**
* Enumeration for format values for type string in JSON Table Schema
* @see <a href="http://specs.frictionlessdata.io/json-table-schema/">JSON Table Schema</a>
*/
public enum StringFormat {
DEFAULT(null),
EMAIL("email"),
URI("uri"),
BINARY("binary"),
UUID("uuid");
private String externalValue;
StringFormat(String externalValue) {
this.externalValue = externalValue;
}
public String getExternalValue() {
return externalValue;
}
public static StringFormat fromExternalValue(String externalValue) {
if (externalValue != null) {
for (StringFormat value : StringFormat.values()) {
if (externalValue.equals(value.getExternalValue())) {
return value;
}
}
}
return DEFAULT;
}
}
@@ -1,48 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.configuration;
import com.google.gson.annotations.SerializedName;
/**
* Types of JSON Table Schema
* @see <a href="http://specs.frictionlessdata.io/json-table-schema/">JSON Table Schema</a>
*/
public enum Type {
@SerializedName("string")STRING,
@SerializedName("integer")INTEGER,
@SerializedName("number")NUMBER,
@SerializedName("date")DATE,
@SerializedName("datetime")DATETIME,
@SerializedName("time")TIME
// TODO: currently not supported
// @SerializedName("object") OBJECT,
// @SerializedName("array") ARRAY,
// @SerializedName("duration") DURATION,
// @SerializedName("geopoint") GEOPOINT,
// @SerializedName("geojson") GEOJSON
}
@@ -1,81 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation.configuration;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.List;
/**
* Configuration based on JSON Table Schema
* @see <a href="http://specs.frictionlessdata.io/json-table-schema/">JSON Table Schema</a>
*/
public class ValidationConfiguration {
@SerializedName("fields")
private Field[] fields;
public Field[] getFields() {
return fields;
}
public void setFields(Field[] fields) {
this.fields = fields;
}
public Field getFieldConfiguration(String column) {
for (Field field : fields) {
if (field.getName().equals(column)) {
return field;
}
}
return null;
}
public String[] headerNames() {
if (fields != null) {
List<String> headerNames = new ArrayList<>();
for (Field field : fields) {
headerNames.add(field.getName());
}
return headerNames.toArray(new String[headerNames.size()]);
}
return null;
}
public void setHeaderNames(String[] header) {
fields = new Field[header.length];
int i = 0;
for (String headerName: header) {
fields[i] = new Field();
fields[i].setName(headerName);
i++;
}
}
}
-26
View File
@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error">
<Properties>
<Property name="filename">smartcsv.log</Property>
</Properties>
<ThresholdFilter level="trace"/>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<File name="File" fileName="${filename}" bufferedIO="true">
<PatternLayout>
<pattern>%d %p %C{1.} [%t] %m%n</pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="File"/>
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
@@ -1,101 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="600.0" spacing="4.0" xmlns="http://javafx.com/javafx/8.0.76-ea" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label text="Thanks for contributions:">
<font>
<Font size="18.0" />
</font>
<VBox.margin>
<Insets top="8.0" />
</VBox.margin>
</Label>
<Label text="AOE Takashi (https://github.com/aoetk)" />
<Label text="Hasan Kara (https://github.com/haisi)" />
<Label text="apixandru (https://github.com/apixandru)" />
<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 maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="20.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="junit" />
<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="FastCSV" GridPane.rowIndex="4" />
<Hyperlink onAction="#openLinkInBrowser" text="https://github.com/osiegmar/FastCSV" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<Label text="Gson" GridPane.rowIndex="5" />
<Hyperlink onAction="#openLinkInBrowser" text="https://github.com/google/gson/" GridPane.columnIndex="1" GridPane.rowIndex="5" />
<Label text="commons-validator" GridPane.rowIndex="6" />
<Hyperlink onAction="#openLinkInBrowser" text="https://commons.apache.org/proper/commons-validator/" GridPane.columnIndex="1" GridPane.rowIndex="6" />
<Label text="fontawesomefx" GridPane.rowIndex="7" />
<Hyperlink onAction="#openLinkInBrowser" text="https://bitbucket.org/Jerady/fontawesomefx" GridPane.columnIndex="1" GridPane.rowIndex="7" />
<Label text="ControlsFX" GridPane.rowIndex="8" />
<Hyperlink onAction="#openLinkInBrowser" text="http://fxexperience.com/controlsfx/" GridPane.columnIndex="1" GridPane.rowIndex="8" />
<Label text="Apache Log4j 2" GridPane.rowIndex="9" />
<Hyperlink onAction="#openLinkInBrowser" text="http://logging.apache.org/log4j/2.x/" GridPane.columnIndex="1" GridPane.rowIndex="9" />
<Label text="RichTextFX" GridPane.rowIndex="10" />
<Hyperlink onAction="#openLinkInBrowser" text="https://github.com/TomasMikula/RichTextFX" GridPane.columnIndex="1" GridPane.rowIndex="10" />
</children>
<padding>
<Insets bottom="4.0" left="8.0" right="8.0" top="4.0" />
</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-2021 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>
@@ -1,11 +0,0 @@
application.name = SmartCSV.fx
application.version = 1.4.0
# fxml views
fxml.smartcvs.view = /ninja/javafx/smartcsv/fx/smartcsv.fxml
fxml.smartcvs.about.view = /ninja/javafx/smartcsv/fx/about/about.fxml
fxml.smartcvs.preferences.view = /ninja/javafx/smartcsv/fx/preferences/preferences.fxml
fxml.smartcvs.validation.editor.view = /ninja/javafx/smartcsv/fx/validation/validationEditor.fxml
# resources
resource.main = ninja.javafx.smartcsv.fx.smartcsv
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?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>
<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.ignoreEmptyLines" GridPane.rowIndex="2" />
<CheckBox fx:id="ignoreEmptyLines" mnemonicParsing="false" text="" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Label text="%preferences.fileEncoding" GridPane.rowIndex="3" />
<ComboBox fx:id="fileEncoding" editable="true" prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="3" />
</children>
<padding>
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
</padding>
</GridPane>
@@ -1,229 +0,0 @@
.table-view .list-view {
-fx-background-color: -fx-background;
-fx-padding: 1;
}
.table-view .list-cell {
-fx-padding: 1.0em 1.0em 1.0em 1.0em;
}
.table-view .list-cell:odd {
-fx-background: -fx-control-inner-background-alt;
}
.table-view .list-cell:even {
-fx-background: -fx-control-inner-background;
}
.open-icon {
-glyph-name: "FILE_IMPORT";
-glyph-size: 16px;
}
.file-document-icon {
-glyph-name: "FILE_DOCUMENT";
-glyph-size: 16px;
}
.config-icon {
-glyph-name: "CLIPBOARD";
-glyph-size: 16px;
}
.create-config-icon {
-glyph-name: "STAR";
-glyph-size: 10px;
}
.load-config-icon {
-glyph-name: "ARROW_UP_BOLD";
-glyph-size: 10px;
}
.save-config-icon {
-glyph-name: "ARROW_DOWN_BOLD";
-glyph-size: 10px;
}
.save-icon {
-glyph-name: "FILE_EXPORT";
-glyph-size: 16px;
}
.exit-icon {
-glyph-name: "EXIT_TO_APP";
-glyph-size: 16px;
}
.info-icon {
-glyph-name: "INFORMATION_OUTLINE";
-glyph-size: 16px;
}
.config-check-icon {
-glyph-name: "CLIPBOARD_CHECK";
-glyph-size: 16px;
}
.preferences-icon {
-glyph-name: "SETTINGS";
-glyph-size: 16px;
}
.delete-icon {
-glyph-name: "TABLE_ROW_REMOVE";
-glyph-size: 16px;
}
.add-icon {
-glyph-name: "TABLE_ROW_PLUS_AFTER";
-glyph-size: 16px;
}
.goto-icon {
-glyph-name: "SUBDIRECTORY_ARROW_RIGHT";
-glyph-size: 16px;
}
.export-icon {
-glyph-name: "BUG";
-glyph-size: 16px;
}
/* toolbar customization based on http://fxexperience.com/2012/02/customized-segmented-toolbar-buttons/ */
#background {
-light-black: rgb(74, 75, 78);
-dark-highlight: rgb(87, 89, 92);
-dark-black: rgb(39, 40, 40);
-darkest-black: rgb(5, 5, 5);
-mid-gray: rgb(216, 222, 227);
-fx-background-color: -mid-gray;
}
.tool-bar {
-fx-base: -dark-black;
-fx-font-size: 12px;
-fx-background-color:
linear-gradient(to bottom, derive(-fx-base,-30%), derive(-fx-base,-60%)),
linear-gradient(to bottom, -light-black 2%, -dark-black 98%);
-fx-background-insets: 0, 0 0 1 0;
-fx-padding: .6em 0.416667em .6em 0.416667em;
-fx-effect: dropshadow(two-pass-box,black,5,.2,0,0);
}
.tool-bar .open-icon {
-glyph-size: 16px;
-fx-fill: white;
}
.tool-bar .config-icon {
-glyph-size: 16px;
-fx-fill: white;
}
.menu-item .load-config-icon,
.menu-item .save-config-icon,
.menu-item .create-config-icon
{
-fx-fill: white;
}
.tool-bar .save-icon {
-glyph-size: 16px;
-fx-fill: white;
}
.tool-bar .preferences-icon {
-glyph-size: 16px;
-fx-fill: white;
}
.tool-bar .exit-icon {
-glyph-size: 16px;
-fx-fill: white;
}
.tool-bar .delete-icon {
-glyph-size: 16px;
-fx-fill: white;
}
.tool-bar .add-icon {
-glyph-size: 16px;
-fx-fill: white;
}
.tool-bar .export-icon {
-glyph-size: 16px;
-fx-fill: white;
}
.segmented-button-bar .button {
-fx-background-color:
-darkest-black,
-dark-highlight,
linear-gradient(to bottom, -light-black 2%, -dark-black 98%);
-fx-background-insets: 0, 1 1 1 0, 2 1 1 1;
-fx-background-radius: 0;
-fx-padding: 0.4em 1.833333em 0.4em 1.833333em;
}
.segmented-button-bar .button.first {
-fx-background-insets: 0, 1, 2 1 1 1;
-fx-background-radius: 3 0 0 3, 2 0 0 2, 2 0 0 2;
}
.segmented-button-bar .button.last {
-fx-background-insets: 0, 1 1 1 0, 2 1 1 1;
-fx-background-radius: 0 3 3 0, 0 2 2 0, 0 2 2 0;
}
.segmented-button-bar .button:pressed {
-fx-background-color:
-darkest-black,
rgb(55, 57, 58),
linear-gradient(to top, -light-black 2%, -dark-black 98%);
}
.tool-bar .spacer {
-fx-padding: 0 5.417em 0 0;
}
.tooltip {
-fx-background-radius: 2 2 2 2;
-fx-background-color: linear-gradient(#eeeeee, #aaaaaa);
-fx-text-fill: black;
-fx-font-size: 12px;
-fx-padding: 10 10 10 10;
}
.keyword {
-fx-fill: purple;
-fx-font-weight: bold;
}
.semicolon {
-fx-font-weight: bold;
}
.paren {
-fx-fill: firebrick;
-fx-font-weight: bold;
}
.bracket {
-fx-fill: darkgreen;
-fx-font-weight: bold;
}
.brace {
-fx-fill: teal;
-fx-font-weight: bold;
}
.string {
-fx-fill: blue;
}
.comment {
-fx-fill: cadetblue;
}
.paragraph-box:has-caret {
-fx-background-color: #f2f9fc;
}
@@ -1,302 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import de.jensd.fx.glyphs.*?>
<?import de.jensd.fx.glyphs.materialdesignicons.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane fx:id="applicationPane" maxHeight="-Infinity" maxWidth="1000.0" minHeight="700.0" minWidth="-Infinity" prefHeight="700.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/8.0.101" xmlns:fx="http://javafx.com/fxml/1">
<top>
<VBox id="background" prefWidth="100.0" BorderPane.alignment="CENTER">
<children>
<MenuBar useSystemMenuBar="true">
<menus>
<Menu mnemonicParsing="false" text="%menu.file">
<items>
<MenuItem mnemonicParsing="false" onAction="#openCsv" text="%menu.open.csv">
<graphic>
<MaterialDesignIconView styleClass="open-icon" />
</graphic>
</MenuItem>
<MenuItem fx:id="saveMenuItem" disable="true" mnemonicParsing="false" onAction="#saveCsv" text="%menu.save">
<graphic>
<MaterialDesignIconView styleClass="save-icon" />
</graphic>
</MenuItem>
<MenuItem fx:id="saveAsMenuItem" disable="true" mnemonicParsing="false" onAction="#saveAsCsv" text="%menu.save.as">
<graphic>
<MaterialDesignIconView styleClass="save-icon" />
</graphic>
</MenuItem>
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem fx:id="createConfigMenuItem" disable="true" mnemonicParsing="false" onAction="#createConfig" text="%menu.create.config">
<graphic>
<GlyphsStack>
<children>
<MaterialDesignIconView styleClass="config-icon" />
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="create-config-icon" />
</children>
</GlyphsStack>
</graphic>
</MenuItem>
<MenuItem fx:id="loadConfigMenuItem" disable="true" mnemonicParsing="false" onAction="#openConfig" text="%menu.open.config">
<graphic>
<GlyphsStack>
<children>
<MaterialDesignIconView styleClass="config-icon" />
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="load-config-icon" />
</children>
</GlyphsStack>
</graphic>
</MenuItem>
<MenuItem fx:id="saveConfigMenuItem" disable="true" mnemonicParsing="false" onAction="#saveConfig" text="%menu.save.config">
<graphic>
<GlyphsStack>
<children>
<MaterialDesignIconView styleClass="config-icon" />
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="save-config-icon" />
</children>
</GlyphsStack>
</graphic>
</MenuItem>
<MenuItem fx:id="saveAsConfigMenuItem" disable="true" mnemonicParsing="false" onAction="#saveAsConfig" text="%menu.save.as.config">
<graphic>
<GlyphsStack>
<children>
<MaterialDesignIconView styleClass="config-icon" />
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="save-config-icon" />
</children>
</GlyphsStack>
</graphic>
</MenuItem>
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem mnemonicParsing="false" onAction="#preferences" text="%menu.preferences">
<graphic>
<MaterialDesignIconView styleClass="preferences-icon" />
</graphic>
</MenuItem>
<MenuItem fx:id="exportMenuItem" disable="true" mnemonicParsing="false" onAction="#export" text="%menu.export">
<graphic>
<MaterialDesignIconView styleClass="export-icon" />
</graphic>
</MenuItem>
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem mnemonicParsing="false" onAction="#close" text="%menu.close">
<graphic>
<MaterialDesignIconView styleClass="exit-icon" />
</graphic>
</MenuItem>
</items>
</Menu>
<Menu mnemonicParsing="false" text="%menu.edit">
<items>
<MenuItem fx:id="deleteRowMenuItem" disable="true" mnemonicParsing="false" onAction="#deleteRow" text="%menu.delete.row">
<graphic>
<MaterialDesignIconView styleClass="delete-icon" />
</graphic>
</MenuItem>
<MenuItem fx:id="addRowMenuItem" disable="true" mnemonicParsing="false" onAction="#addRow" text="%menu.add.row">
<graphic>
<MaterialDesignIconView styleClass="add-icon" />
</graphic>
</MenuItem>
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem fx:id="gotoLineMenuItem" disable="true" mnemonicParsing="false" onAction="#gotoLine" text="%menu.goto.line">
<graphic>
<MaterialDesignIconView styleClass="goto-icon" />
</graphic>
</MenuItem>
</items>
</Menu>
<Menu mnemonicParsing="false" text="%menu.help">
<items>
<MenuItem mnemonicParsing="false" onAction="#about" text="%menu.about">
<graphic>
<MaterialDesignIconView styleClass="info-icon" />
</graphic>
</MenuItem>
</items>
</Menu>
</menus>
</MenuBar>
<ToolBar prefHeight="40.0" prefWidth="200.0">
<HBox styleClass="segmented-button-bar">
<Button mnemonicParsing="false" onAction="#openCsv" styleClass="first">
<tooltip>
<Tooltip text="%menu.open.csv" />
</tooltip>
<graphic>
<MaterialDesignIconView styleClass="open-icon" />
</graphic>
</Button>
<Button fx:id="saveButton" disable="true" mnemonicParsing="false" onAction="#saveCsv">
<tooltip>
<Tooltip text="%menu.save" />
</tooltip>
<graphic>
<MaterialDesignIconView styleClass="save-icon" />
</graphic>
</Button>
<Button fx:id="saveAsButton" disable="true" mnemonicParsing="false" onAction="#saveAsCsv" styleClass="last" text="...">
<tooltip>
<Tooltip text="%menu.save.as" />
</tooltip>
<graphic>
<MaterialDesignIconView styleClass="save-icon" />
</graphic>
</Button>
</HBox>
<Region styleClass="spacer" />
<HBox styleClass="segmented-button-bar">
<Button fx:id="createConfigButton" disable="true" mnemonicParsing="false" onAction="#createConfig">
<tooltip>
<Tooltip text="%menu.create.config" />
</tooltip>
<graphic>
<GlyphsStack>
<children>
<MaterialDesignIconView styleClass="config-icon" />
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="create-config-icon" />
</children>
</GlyphsStack>
</graphic>
</Button>
<Button fx:id="loadConfigButton" disable="true" mnemonicParsing="false" onAction="#openConfig">
<tooltip>
<Tooltip text="%menu.open.config" />
</tooltip>
<graphic>
<GlyphsStack>
<children>
<MaterialDesignIconView styleClass="config-icon" />
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="load-config-icon" />
</children>
</GlyphsStack>
</graphic>
</Button>
<Button fx:id="saveConfigButton" disable="true" mnemonicParsing="false" onAction="#saveConfig">
<tooltip>
<Tooltip text="%menu.save.config" />
</tooltip>
<graphic>
<GlyphsStack>
<children>
<MaterialDesignIconView styleClass="config-icon" />
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="save-config-icon" />
</children>
</GlyphsStack>
</graphic>
</Button>
<Button fx:id="saveAsConfigButton" disable="true" mnemonicParsing="false" onAction="#saveAsConfig" styleClass="last" text="...">
<tooltip>
<Tooltip text="%menu.save.as.config" />
</tooltip>
<graphic>
<GlyphsStack>
<children>
<MaterialDesignIconView styleClass="config-icon" />
<MaterialDesignIconView style="-fx-opacity: 0.7;" styleClass="save-config-icon" />
</children>
</GlyphsStack>
</graphic>
</Button>
</HBox>
<Region styleClass="spacer" />
<HBox styleClass="segmented-button-bar">
<Button fx:id="deleteRowButton" disable="true" mnemonicParsing="false" onAction="#deleteRow" styleClass="first">
<tooltip>
<Tooltip text="%menu.delete.row" />
</tooltip>
<graphic>
<MaterialDesignIconView styleClass="delete-icon" />
</graphic>
</Button>
<Button fx:id="addRowButton" disable="true" mnemonicParsing="false" onAction="#addRow" styleClass="last">
<tooltip>
<Tooltip text="%menu.add.row" />
</tooltip>
<graphic>
<MaterialDesignIconView styleClass="add-icon" />
</graphic>
</Button>
</HBox>
<Region styleClass="spacer" />
<HBox styleClass="segmented-button-bar">
<Button mnemonicParsing="false" onAction="#preferences" styleClass="first">
<tooltip>
<Tooltip text="%menu.preferences" />
</tooltip>
<graphic>
<MaterialDesignIconView styleClass="preferences-icon" />
</graphic>
</Button>
<Button fx:id="exportButton" disable="true" mnemonicParsing="false" onAction="#export">
<tooltip>
<Tooltip text="%menu.export" />
</tooltip>
<graphic>
<MaterialDesignIconView styleClass="export-icon" />
</graphic>
</Button>
<Button mnemonicParsing="false" onAction="#close" styleClass="last">
<tooltip>
<Tooltip text="%menu.close" />
</tooltip>
<graphic>
<MaterialDesignIconView styleClass="exit-icon" />
</graphic>
</Button>
</HBox>
</ToolBar>
</children>
</VBox>
</top>
<center>
<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>
</center>
<left>
</left>
<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="NEVER" minWidth="10.0" />
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" />
<ColumnConstraints hgrow="NEVER" minWidth="10.0" />
<ColumnConstraints fillWidth="false" halignment="RIGHT" hgrow="NEVER" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints fillWidth="false" halignment="RIGHT" hgrow="NEVER" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<MaterialDesignIconView styleClass="file-document-icon" GridPane.hgrow="NEVER" />
<Label text="%stateline.csv" GridPane.columnIndex="1" GridPane.hgrow="NEVER" />
<Label fx:id="csvName" GridPane.columnIndex="2" GridPane.hgrow="ALWAYS" />
<MaterialDesignIconView styleClass="config-check-icon" GridPane.columnIndex="3" GridPane.hgrow="NEVER" />
<Label text="%stateline.configuration" GridPane.columnIndex="4" GridPane.hgrow="NEVER" />
<Label fx:id="configurationName" GridPane.columnIndex="5" GridPane.hgrow="ALWAYS" />
<Label text="%lineNumber" GridPane.columnIndex="7" />
<Label fx:id="currentLineNumber" text="" GridPane.columnIndex="8" />
<Label text="%totalNumberOfLines" GridPane.columnIndex="9" />
<Label fx:id="totalNumberOfLines" text="0" GridPane.columnIndex="10" />
</children>
<BorderPane.margin>
<Insets bottom="4.0" left="8.0" right="8.0" top="4.0" />
</BorderPane.margin>
</GridPane>
</bottom>
</BorderPane>
@@ -1,105 +0,0 @@
menu.open.csv = Open CSV File
menu.open.config = Open Validation Config
menu.create.config = Create Validation Config
menu.save = Save
menu.save.as = Save As ...
menu.save.config = Save Validation Config
menu.save.as.config = Save Validation Config as ...
menu.close = Close
menu.about = About
menu.file = File
menu.edit = Edit
menu.help = Help
menu.preferences = Preferences
menu.delete.row = Delete row
menu.add.row = Add row
menu.goto.line = Goto line
menu.export = Export error log
title.validation.errors = Validation Errors:
stateline.csv = CSV:
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.changes.title = Discard changes
dialog.changes.header.text = Do you want to discard changes?
dialog.changes.text = There are changes made to the csv file. If you open a new file, the changes are lost!
dialog.preferences.title = Preferences
dialog.preferences.header.text = Preferences
dialog.goto.line.title = Go to line
dialog.goto.line.header.text = Go to given line (max. {0}) and select line!
dialog.goto.line.label = Line:
preferences.quoteChar = Quote character:
preferences.delimiterChar = Delimiter character:
preferences.ignoreEmptyLines = Ignore empty lines:
preferences.surroundingSpacesNeedQuotes = Surrounding spaces need quotes:
preferences.quoteMode = Quote mode:
preferences.fileEncoding = File encoding:
# 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.email = should be an email address
validation.message.alphanumeric = should be alphanumeric
validation.message.groovy.exception = groovy script '{0}' throws exception: {1}
validation.message.groovy.return.null = groovy script '{0}' returns null
validation.message.min.length = has not min length of {0}
validation.message.max.length = has not max length of {0}
validation.message.date.format = is not a date of format {0}
validation.message.regexp = does not match {0}
validation.message.uniqueness.multiple = value {0} is not unique (found in rows {1})
validation.message.uniqueness.single = value {0} is not unique (found in row {1})
validation.message.uri = should be an uri
validation.message.uuid = should be an uuid
validation.message.binary = should be a base64 encoded string representing binary data
validation.message.header.length = number of headers is not correct! there are {0} but there should be {1}
validation.message.header.match = header number {0} does not match "{1}" should be "{2}"
validation.message.value.of = Value {0} is not part of this list {1}
validation.rule.label.not_empty = not empty
validation.rule.label.integer = integer
validation.rule.label.double = double
validation.rule.label.minlength = minimum length:
validation.rule.label.maxlength = maximum length:
validation.rule.label.dateformat = date format:
validation.rule.label.alphanumeric = alphanumeric
validation.rule.label.regexp = regular expression:
validation.rule.label.value_of = value in list:
validation.rule.label.groovy = groovy:
validation.rules.active = active
validation.rules.name = rule
validation.rules.value = value
validation.rule.label.unique = Unique in column
validation.rule.format = Format:
validation.rule.type = Type:
dialog.validation.rules.title = Validation rules
dialog.validation.rules.header = Validation rules of column "{0}"
context.menu.edit.column.rules = Edit rules
lineNumber = Selected line:
totalNumberOfLines = Lines:
log.header.message = {0} has {1} errors
log.message = row {0} column {1} : {2}
column = column
format.type.DEFAULT = default
format.type.EMAIL = email
format.type.URI = uri
format.type.BINARY = binary
format.type.UUID = uuid
@@ -1,115 +0,0 @@
# 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.create.config = Pr\u00fcfkonfiguration erzeugen
menu.save = Speichern
menu.save.as = Speichern als ...
menu.save.config = Pr\u00fcfkonfiguration speichern
menu.save.as.config = Pr\u00fcfkonfiguration speichern als ...
menu.close = Beenden
menu.about = \u00dcber ...
menu.file = Datei
menu.edit = Bearbeiten
menu.help = Hilfe
menu.preferences = Einstellungen
menu.delete.row = Zeile l\u00f6schen
menu.add.row = Zeile hinzuf\u00fcgen
menu.goto.line = Springe zur Zeile
menu.export = Export Fehlerdatei
title.validation.errors = Fehler in der Datei:
stateline.csv = CSV:
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.goto.line.title = Springe zur Zeile
dialog.goto.line.header.text = Zur angegebenen Zeile (max. {0}) springen und ausw\u00e4hlen!
dialog.goto.line.label = Zeile:
dialog.exit.title = Anwendung beenden
dialog.exit.header.text = M\u00f6chten Sie wirklich die Anwendung beenden?
dialog.exit.text = Es gibt noch ungespeicherte \u00c4nderungen, die verloren gehen, wenn Sie die Anwendung jetzt beenden.
dialog.changes.title = Änderungen verwerfen
dialog.changes.header.text = Wollen Sie Ihre Änderungen verwerfen?
dialog.changes.text = Es gibt noch ungespeicherte \u00c4nderungen, die verloren gehen, wenn Sie die Datei laden.
preferences.quoteChar = Einfassungszeichen:
preferences.delimiterChar = Trennzeichen:
preferences.ignoreEmptyLines = Leere Zeilen ignorieren:
preferences.surroundingSpacesNeedQuotes = Leerzeichen einfassen:
preferences.quoteMode = Einfassungsmodus:
preferences.fileEncoding = Dateicodierung:
# 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.email = Muss eine Email-Adresse sein
validation.message.alphanumeric = Darf nur Zahlen und Buchstaben enthalten.
validation.message.groovy.exception = groovy script '{0}' wirft folgenden Fehler: {1}
validation.message.groovy.return.null = groovy script '{0}' meldet "null"
validation.message.min.length = Hat nicht die minimale L\u00e4nge von {0}
validation.message.max.length = Hat nicht die maximale L\u00e4nge von {0}
validation.message.date.format = Das Datumsformat entspricht nicht {0}
validation.message.regexp = entspricht nicht dem regul\u00e4ren Ausdruck {0}
validation.message.uniqueness.multiple = Wert {0} ist nicht einmalig (gefunden in den Zeilen {1})
validation.message.uniqueness.single = Wert {0} ist nicht einmalig (gefunden in Zeile {1})
validation.message.uri = Muss eine URI sein
validation.message.uuid = Muss eine UUID sein
validation.message.binary = Muss ein base64 encoded Text sein, der bin\u00e4re Daten enth\u00e4lt
validation.message.header.length = Anzahl der \u00dcberschriften ist nicht korrekt! Es sind {0} aber es sollten {1} sein
validation.message.header.match = \u00dcberschrift in Spalte {0} stimmt nicht. "{1}" sollte "{3}" sein
validation.message.value.of = Der Wert {0} ist nicht in der Liste {1} enthalten
validation.rule.label.not_empty = Nicht leer
validation.rule.label.integer = Zahl
validation.rule.label.double = Gleitkommazahl
validation.rule.label.minlength = Minimale L\u00e4nge:
validation.rule.label.maxlength = Maximale L\u00e4nge:
validation.rule.label.dateformat = Datumsformat:
validation.rule.label.alphanumeric = Nur Zahlen und Buchstaben:
validation.rule.label.regexp = Regul\u00e4rer Ausdruck:
validation.rule.label.value_of = In der Liste:
validation.rule.label.groovy = groovy:
validation.rules.active = Aktiv
validation.rules.name = Regel
validation.rules.value = Wert
validation.rule.label.unique = Einmalig in Spalte
validation.rule.format = Format:
validation.rule.type = Typ:
dialog.validation.rules.title = Pr\u00fcfregeln
dialog.validation.rules.header = Pr\u00fcfregeln f\u00fcr die Spalte "{0}"
context.menu.edit.column.rules = Pr\u00fcfregeln bearbeiten
lineNumber = Ausgew\u00e4hlte Zeile:
totalNumberOfLines = Zeilen:
log.header.message = {0} hat {1} Fehler
log.message = Zeile {0} Spalte {1} : {2}
column = Spalte
format.type.DEFAULT = Standard
format.type.EMAIL = Email
format.type.URI = URI
format.type.BINARY = Bin\u00e4r
format.type.UUID = UUID
@@ -1,69 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.Spinner?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import org.fxmisc.richtext.CodeArea?>
<GridPane hgap="20.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="800.0" vgap="6.0" xmlns="http://javafx.com/javafx/8.0.76-ea" xmlns:fx="http://javafx.com/fxml/1">
<columnConstraints>
<ColumnConstraints halignment="LEFT" hgrow="NEVER" />
<ColumnConstraints halignment="LEFT" hgrow="ALWAYS" />
<ColumnConstraints halignment="LEFT" hgrow="NEVER" />
<ColumnConstraints halignment="LEFT" hgrow="ALWAYS" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" valignment="TOP" vgrow="ALWAYS" />
<RowConstraints />
</rowConstraints>
<children>
<Label text="%validation.rule.type" GridPane.columnSpan="2" GridPane.halignment="LEFT" GridPane.hgrow="ALWAYS" />
<Label text="%validation.rule.format" GridPane.columnSpan="2" GridPane.halignment="LEFT" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" />
<ComboBox fx:id="typeComboBox" maxWidth="1.7976931348623157E308" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.halignment="LEFT" GridPane.hgrow="ALWAYS" />
<ComboBox fx:id="formatComboBox" prefWidth="150.0" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="1" visible="false" />
<TextField fx:id="formatTextField" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="1" visible="false" />
<CheckBox fx:id="enableNotEmptyRule" mnemonicParsing="false" text="%validation.rule.label.not_empty" GridPane.rowIndex="3" />
<CheckBox fx:id="enableUniqueRule" mnemonicParsing="false" text="%validation.rule.label.unique" GridPane.columnIndex="2" GridPane.rowIndex="3" />
<CheckBox fx:id="enableMinLengthRule" mnemonicParsing="false" text="%validation.rule.label.minlength" GridPane.rowIndex="4" />
<Spinner fx:id="minLengthSpinner" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<CheckBox fx:id="enableMaxLengthRule" mnemonicParsing="false" text="%validation.rule.label.maxlength" GridPane.columnIndex="2" GridPane.rowIndex="4" />
<Spinner fx:id="maxLengthSpinner" GridPane.columnIndex="3" GridPane.rowIndex="4" />
<CheckBox fx:id="enableRegexpRule" mnemonicParsing="false" text="%validation.rule.label.regexp" GridPane.rowIndex="5" />
<TextField fx:id="regexpRuleTextField" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="5" />
<CheckBox fx:id="enableValueOfRule" mnemonicParsing="false" text="%validation.rule.label.value_of" GridPane.rowIndex="6" />
<TextField fx:id="valueOfRuleTextField" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="6" />
<CheckBox fx:id="enableGroovyRule" mnemonicParsing="false" text="%validation.rule.label.groovy" GridPane.rowIndex="7">
<GridPane.margin>
<Insets top="8.0" />
</GridPane.margin>
</CheckBox>
<CodeArea fx:id="groovyRuleTextArea" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="7">
<GridPane.margin>
<Insets top="8.0" />
</GridPane.margin>
</CodeArea>
<Separator prefWidth="200.0" GridPane.columnSpan="4" GridPane.rowIndex="2" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<stylesheets>
<URL value="@/ninja/javafx/smartcsv/fx/smartcsv.css" />
</stylesheets>
</GridPane>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 750 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

@@ -1,109 +0,0 @@
package ninja.javafx.smartcsv.files;
import ninja.javafx.smartcsv.FileReader;
import ninja.javafx.smartcsv.FileWriter;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.File;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.*;
public class FileStorageTest {
private FileReader<String> reader;
private FileWriter<String> writer;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// subject under test
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private FileStorage<String> sut;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// init
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@BeforeEach
public void initialize() {
reader = mock(FileReader.class);
writer = mock(FileWriter.class);
sut = new FileStorage<>(reader, writer);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Test
public void setFile_ShouldStoreFile() {
// pre execution assertion
assertThat("get file returns null", sut.getFile(), nullValue());
assertThat("property is null", sut.fileProperty().isNull().get(), equalTo(true));
// execution
final File file = new File("file");
sut.setFile(file);
// assertion
assertThat("get file returns the file", sut.getFile(), sameInstance(file));
assertThat("property is not null", sut.fileProperty().isNull().get(), equalTo(false));
}
@Test
public void load_ShouldReadContentFromReader() throws Exception {
// setup
final File file = new File("file");
sut.setFile(file);
when(reader.getContent()).thenReturn("CONTENT");
// execution
sut.load();
// assertion
verify(reader).read(file);
assertThat("content is set", sut.getContent(), equalTo("CONTENT"));
}
@Test
public void load_ShouldResetFileChangedProperty() throws Exception {
// setup
sut.setFileChanged(true);
when(reader.getContent()).thenReturn("CONTENT");
// execution
sut.load();
// assertion
assertThat("file changed is reset", sut.isFileChanged(), equalTo(false));
}
@Test
public void save_ShouldWriteContentToWriter() throws Exception {
// setup
final String content = "CONTENT";
sut.setContent(content);
final File file = new File("file");
sut.setFile(file);
// execution
sut.save();
// assertion
verify(writer).setContent(content);
verify(writer).write(file);
}
@Test
public void save_ShouldResetFileChangedProperty() throws Exception {
// setup
sut.setFileChanged(true);
// execution
sut.save();
// assertion
assertThat("file changed is reset", sut.isFileChanged(), equalTo(false));
}
}
@@ -1,87 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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 org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
/**
* unit test for the csv model
*/
public class CSVModelTest {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constants
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private static final String TESTHEADER = "TESTHEADER";
private static final String TESTVALUE = "TESTVALUE";
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// subject under test
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private 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()));
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void setup_model_with_one_row_one_column_and_value() {
sut.setHeader(new String[] {TESTHEADER});
sut.addRow().addValue(TESTHEADER, TESTVALUE);
}
}
@@ -1,41 +0,0 @@
package ninja.javafx.smartcsv.fx.table.model;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.is;
/**
* unit test for row class
*/
public class CSVRowTest {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constants
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private static final String COLUMN = "COLUMN";
private static final String VALUE = "VALUE";
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// subject under test
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private 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));
}
}
@@ -1,57 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 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.junit.jupiter.api.Test;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static org.junit.jupiter.api.Assertions.*;
public class CharsetHelperTest {
@Test
public void getCharsetName_known_charset() {
String result = CharsetHelper.getCharsetName("UTF-16");
assertEquals(StandardCharsets.UTF_16.name(), result);
assertNotEquals(StandardCharsets.UTF_16.name(), Charset.defaultCharset());
}
@Test
public void getCharsetName_unknown_charset() {
String result = CharsetHelper.getCharsetName("foobar");
assertEquals(Charset.defaultCharset().name(), result);
}
@Test
public void getCharsetName_null_charset() {
String result = CharsetHelper.getCharsetName(null);
assertEquals(Charset.defaultCharset().name(), result);
}
}
@@ -1,107 +0,0 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015-2021 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.validation.configuration.ValidationConfiguration;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.List;
import java.util.stream.Stream;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* unit test for header validator
*/
public class HeaderValidationTest {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ParameterizedTest
@MethodSource("validationConfigurations")
public void validation(String configHeaderNames,
String[] headerNames,
Boolean expectedResult,
List<ValidationMessage> expectedErrors) {
// setup
Gson gson = new GsonBuilder().create();
ValidationConfiguration config = gson.fromJson(configHeaderNames, ValidationConfiguration.class);
Validator sut = new Validator(config, new TestColumnValueProvider());
// execution
ValidationError result = sut.isHeaderValid(headerNames);
// assertion
assertThat(result == null, is(expectedResult));
if (!expectedResult) {
assertTrue(result.getMessages().containsAll(expectedErrors));
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// parameters for tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public static Stream<Arguments> validationConfigurations() {
return Stream.of(
Arguments.of( json(), new String[] {}, true, null ),
Arguments.of( json("a"), new String[] {"a"}, true, null ),
Arguments.of( json("a"), new String[] {"b"}, false, singletonList(new ValidationMessage("validation.message.header.match", "0", "a", "b"))),
Arguments.of( json("a"), new String[] {"a","b"}, false, singletonList(new ValidationMessage("validation.message.header.length", "2", "1"))),
Arguments.of( json("a", "b"), new String[] {"b", "a"}, false, asList(new ValidationMessage("validation.message.header.match", "0", "a", "b"), new ValidationMessage("validation.message.header.match", "1", "b", "a")) )
);
}
@SuppressWarnings("StringConcatenationInLoop")
public static String json(String... headerNames) {
String json = "{ \"fields\": [";
for (String headerName: headerNames) {
json += "{\"name\" : \""+headerName+"\" },";
}
if (headerNames != null && headerNames.length > 0) {
json = json.substring(0, json.length() - 1);
}
json += "]}";
return json;
}
}

Some files were not shown because too many files have changed in this diff Show More