Initial commit

This commit is contained in:
Andreas Billmann
2015-11-28 23:06:14 +01:00
commit 07084bd18e
31 changed files with 2342 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv;
import java.io.File;
import java.io.IOException;
/**
* Created by Andreas on 19.11.2015.
*/
public interface FileReader {
void read(File filename) throws IOException;
}

View File

@@ -0,0 +1,80 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.csv;
import ninja.javafx.smartcsv.FileReader;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import org.springframework.stereotype.Service;
import org.supercsv.io.CsvMapReader;
import org.supercsv.io.ICsvMapReader;
import org.supercsv.prefs.CsvPreference;
import java.io.File;
import java.io.IOException;
import java.util.Map;
/**
* Created by Andreas on 18.11.2015.
*/
@Service
public class CSVFileReader implements FileReader {
private CSVModel model;
@Override
public void read(File file) throws IOException {
ICsvMapReader mapReader = null;
try {
mapReader = new CsvMapReader(new java.io.FileReader(file.getAbsoluteFile()), CsvPreference.EXCEL_NORTH_EUROPE_PREFERENCE);
model = new CSVModel(file.getAbsolutePath());
// the header columns are used as the keys to the Map
String[] header = mapReader.getHeader(true);
model.setHeader(header);
Map<String, String> customerMap;
while ((customerMap = mapReader.read(header)) != null) {
CSVRow row = model.addRow();
for (String column : header) {
row.addValue(column, customerMap.get(column));
}
}
} finally {
if (mapReader != null) {
mapReader.close();
}
}
}
public CSVModel getData() {
return model;
}
}

View File

@@ -0,0 +1,80 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.csv;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import org.springframework.stereotype.Service;
import org.supercsv.io.CsvMapWriter;
import org.supercsv.io.ICsvMapWriter;
import org.supercsv.prefs.CsvPreference;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
import static java.util.stream.Collectors.toMap;
/**
* filewriter for the csv
*/
@Service
public class CSVFileWriter {
public void saveFile(CSVModel model) throws IOException {
ICsvMapWriter mapWriter = null;
try {
mapWriter = new CsvMapWriter(new FileWriter(model.getFilepath()), CsvPreference.EXCEL_NORTH_EUROPE_PREFERENCE);
mapWriter.writeHeader(model.getHeader());
for(CSVRow row: model.getRows()) {
Map<String, String> columns = convertMapFromModel(row);
mapWriter.write(columns, model.getHeader());
}
}
finally {
if( mapWriter != null ) {
mapWriter.close();
}
}
}
/**
* transforms the column map from CSVValue to a simple Map<String,String>
* @param row the row to convert
* @return a simple map for the supercvs writer
*/
private Map<String, String> convertMapFromModel(CSVRow row) {
return row.getColumns().entrySet().stream()
.collect(
toMap(
Map.Entry::getKey,
e -> e.getValue().getValue().getValue() != null ? e.getValue().getValue().getValue() : ""
)
);
}
}

View File

@@ -0,0 +1,72 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import java.io.IOException;
import java.io.InputStream;
import java.util.ResourceBundle;
public abstract class FXMLController implements InitializingBean, Initializable {
protected Node view;
protected String fxmlFilePath;
protected String resourcePath;
public abstract void setFxmlFilePath(String filePath);
@Value("${resource.main}")
public void setResourceBundle(String resourcePath) {
this.resourcePath = resourcePath;
}
@Override
public void afterPropertiesSet() throws Exception {
loadFXML();
}
protected final void loadFXML() throws IOException {
try (InputStream fxmlStream = getClass().getResourceAsStream(fxmlFilePath)) {
FXMLLoader loader = new FXMLLoader();
loader.setResources(ResourceBundle.getBundle(this.resourcePath));
loader.setController(this);
this.view = (loader.load(fxmlStream));
} catch (Throwable t) {
t.printStackTrace();
}
}
public Node getView() {
return view;
}
}

View File

@@ -0,0 +1,84 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.springframework.context.annotation.*;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
@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");
try {
showUI(primaryStage, name, version);
} catch (Exception e) {
e.printStackTrace();
}
}
@Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Override
public void stop() throws Exception {
if (appContext != null) {
appContext.close();
}
super.stop();
}
public static void main(String[] args) {
launch(args);
}
private void showUI(Stage primaryStage, String name, String version) {
SmartCSVController smartCVSController = appContext.getBean(SmartCSVController.class);
Scene scene = new Scene((Parent) smartCVSController.getView());
primaryStage.setScene(scene);
primaryStage.setTitle(String.format("%s %s", name, version));
primaryStage.show();
}
}

View File

@@ -0,0 +1,290 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser;
import ninja.javafx.smartcsv.FileReader;
import ninja.javafx.smartcsv.csv.CSVFileReader;
import ninja.javafx.smartcsv.csv.CSVFileWriter;
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.CSVValue;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import ninja.javafx.smartcsv.validation.ValidationFileReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import static javafx.application.Platform.runLater;
/**
* main controller of the application
*/
@Component
public class SmartCSVController extends FXMLController {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// injections
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Autowired
private CSVFileReader csvLoader;
@Autowired
private ValidationFileReader validationLoader;
@Autowired
private CSVFileWriter csvFileWriter;
@FXML
private BorderPane applicationPane;
@FXML
private Label stateline;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// injections
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private ValidationCellFactory cellFactory = new ValidationCellFactory();
private final LoadCSVService loadCSVService = new LoadCSVService();
private final SaveCSVService saveCSVService = new SaveCSVService();
private CSVModel model;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// init
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
public void initialize(URL location, ResourceBundle resources) {
stateline.setVisible(false);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// setter
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Value("${fxml.smartcvs.view}")
@Override
public void setFxmlFilePath(String filePath) {
this.fxmlFilePath = filePath;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// actions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@FXML
public void openCsv(ActionEvent actionEvent) {
loadFile(csvLoader, "CSV files (*.csv)", "*.csv", "Open CSV");
}
@FXML
public void openConfig(ActionEvent actionEvent) {
loadFile(validationLoader, "JSON files (*.json)", "*.json", "Open Validation Configuration");
}
@FXML
public void saveCsv(ActionEvent actionEvent) {
saveCSVService.restart();
}
@FXML
public void saveAsCsv(ActionEvent actionEvent) {
saveFile(csvFileWriter, "CSV files (*.csv)", "*.csv");
}
@FXML
public void close(ActionEvent actionEvent) {
Platform.exit();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void loadFile(FileReader fileReader, String filterText, String filter, String title) {
final FileChooser fileChooser = new FileChooser();
//Set extension filter
final FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(filterText, filter);
fileChooser.getExtensionFilters().add(extFilter);
fileChooser.setTitle(title);
//Show open file dialog
final File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow());
if (file != null) {
loadCSVService.setFile(file);
loadCSVService.setFileReader(fileReader);
loadCSVService.restart();
}
}
private void saveFile(CSVFileWriter writer, String filterText, String filter) {
if (model != null) {
final FileChooser fileChooser = new FileChooser();
//Set extension filter
final FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(filterText, filter);
fileChooser.getExtensionFilters().add(extFilter);
File initfile = new File(model.getFilepath());
fileChooser.setInitialDirectory(initfile.getParentFile());
fileChooser.setInitialFileName(initfile.getName());
fileChooser.setTitle("Save File");
//Show open file dialog
final File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow());
if (file != null) {
model.setFilepath(file.getAbsolutePath());
saveCSVService.restart();
}
}
}
/**
* Creates new table view and add the new content
*/
private void resetContent() {
model = csvLoader.getData();
model.setValidator(validationLoader.getValidator());
TableView<CSVRow> tableView = new TableView<>();
for (String column: model.getHeader()) {
addColumn(column, tableView);
}
tableView.getItems().setAll(model.getRows());
tableView.setEditable(true);
applicationPane.setCenter(tableView);
}
/**
* Adds a column with the given name to the tableview
* @param header name of the column header
* @param tableView the tableview
*/
private void addColumn(String header, TableView tableView) {
TableColumn column = new TableColumn(header);
column.setCellValueFactory(new ObservableMapValueFactory(header));
column.setCellFactory(cellFactory);
column.setEditable(true);
column.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<CSVRow, CSVValue>>() {
@Override
public void handle(TableColumn.CellEditEvent<CSVRow, CSVValue> event) {
event.getTableView().getItems().get(event.getTablePosition().getRow()).
getColumns().get(header).
setValue(event.getNewValue());
}
});
tableView.getColumns().add(column);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// inner class
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Service class for async load of a csv file
*/
private class LoadCSVService extends Service {
private File file = null;
private FileReader fileReader;
public void setFile(File value) {
file = value;
}
public void setFileReader(FileReader fileReader) {
this.fileReader = fileReader;
}
@Override
protected Task createTask() {
return new Task() {
@Override
protected Void call() throws Exception {
if (file != null) {
try {
fileReader.read(file);
runLater(SmartCSVController.this::resetContent);
} catch (IOException ex) {
ex.printStackTrace();
}
}
return null;
}
};
}
}
/**
* Service class for async load of a csv file
*/
private class SaveCSVService extends Service {
@Override
protected Task createTask() {
return new Task() {
@Override
protected Void call() throws Exception {
try {
csvFileWriter.saveFile(model);
runLater(SmartCSVController.this::resetContent);
} catch (IOException ex) {
ex.printStackTrace();
}
return null;
}
};
}
}
}

View File

@@ -0,0 +1,136 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.table;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCode;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
import static javafx.application.Platform.runLater;
/**
* Created by Andreas on 27.11.2015.
*/
public class EditableValidationCell extends TableCell<CSVRow, CSVValue> {
private ValueTextField textField;
@Override
public void startEdit() {
super.startEdit();
setTextField();
runLater(() -> {
textField.requestFocus();
textField.selectAll();
});
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText(getItem().getValue());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
@Override
protected void updateItem(CSVValue item, boolean empty) {
super.updateItem(item, empty);
if (item == null || item.getValid().isValid() || isEditing()) {
setStyle("");
setTooltip(null);
} else if (!item.getValid().isValid()) {
setStyle("-fx-background-color: #ff8888");
setTooltip(new Tooltip(item.getValid().error()));
}
if (item == null || empty) {
setTextInCell(null);
} else {
if (isEditing()) {
setTextField();
textField.setValue(item);
} else {
setTextInCell(item.getValue());
}
}
}
private void setTextField() {
if (textField == null) {
createTextField();
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
private void setTextInCell(String text) {
setGraphic(null);
setText(text);
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
private void createTextField() {
textField = new ValueTextField(getItem());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.setOnKeyPressed(t -> {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(textField.getValue());
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
});
textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue && textField != null) {
commitEdit(textField.getValue());
}
});
}
private class ValueTextField extends TextField {
private CSVValue value;
public ValueTextField(CSVValue value) {
setValue(value);
}
public void setValue(CSVValue value) {
this.value = value;
setText(value.getValue());
}
public CSVValue getValue() {
value.setValue(getText());
return value;
}
}
}

View File

@@ -0,0 +1,53 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.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;
/**
* Created by Andreas on 18.11.2015.
*/
public class ObservableMapValueFactory implements
Callback<TableColumn.CellDataFeatures<CSVRow, CSVValue>, ObjectProperty<CSVValue>> {
private final Object key;
public ObservableMapValueFactory(Object key) {
this.key = key;
}
@Override
public ObjectProperty<CSVValue> call(TableColumn.CellDataFeatures<CSVRow, CSVValue> features) {
CSVRow row = features.getValue();
ObjectProperty<CSVValue> value = row.getColumns().get(key);
return value;
}
}

View File

@@ -0,0 +1,45 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.table;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
/**
* Created by Andreas on 18.11.2015.
*/
public class ValidationCellFactory implements Callback<TableColumn<CSVRow, CSVValue>, TableCell<CSVRow, CSVValue>> {
@Override
public TableCell<CSVRow, CSVValue> call(TableColumn<CSVRow, CSVValue> param) {
return new EditableValidationCell();
}
}

View File

@@ -0,0 +1,121 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.table.model;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import ninja.javafx.smartcsv.validation.ValidationState;
import ninja.javafx.smartcsv.validation.Validator;
/**
* The CSVModel is the client representation for the csv filepath.
* It holds the data in rows, stores the header and manages the validator.
*/
public class CSVModel {
private Validator validator;
private ObservableList<CSVRow> rows = FXCollections.observableArrayList();
private String[] header;
private String filepath;
public CSVModel(String filepath) {
this.filepath = filepath;
}
public String getFilepath() {
return this.filepath;
}
public void setFilepath(String filepath) {
this.filepath = filepath;
}
/**
* sets the validator for the data revalidates
* @param validator the validator for this data
*/
public void setValidator(Validator validator) {
this.validator = validator;
revalidate();
}
/**
* returns the data as a list of rows of the
* @return list of rows
*/
public ObservableList<CSVRow> getRows() {
return rows;
}
/**
* adds a new and empty row
* @return the new row
*/
public CSVRow addRow() {
CSVRow row = new CSVRow();
row.setValidator(validator);
row.setRowNumber(rows.size());
rows.add(row);
return row;
}
/**
* sets the column headers as string array
* @param header the headers of the columns
*/
public void setHeader(String[] header) {
this.header = header;
}
/**
* returns the column headers
* @return the column headers
*/
public String[] getHeader() {
return header;
}
/**
* walks through the data and validates each value
*/
private void revalidate() {
for (CSVRow row: rows) {
row.setValidator(validator);
for (String column: row.getColumns().keySet()) {
CSVValue value = row.getColumns().get(column).getValue();
value.setValidator(validator);
if (validator != null) {
value.setValid(validator.isValid(column, value.getValue()));
} else {
value.setValid(new ValidationState());
}
}
}
}
}

View File

@@ -0,0 +1,90 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.table.model;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import ninja.javafx.smartcsv.validation.Validator;
/**
* This class represents a single row in the csv file.
*/
public class CSVRow {
private Validator validator;
private ObservableMap<String, ObjectProperty<CSVValue>> columns = FXCollections.observableHashMap();
private int rowNumber;
/**
* single row
* @param validator the reference to the validator
*/
public void setValidator(Validator validator) {
this.validator = validator;
}
/**
* sets the row number
* @param rowNumber
*/
public void setRowNumber(int rowNumber) {
this.rowNumber = rowNumber;
}
/**
* return the row number
* @return row number
*/
public int getRowNumber() {
return rowNumber;
}
/**
* returns the columns with data as Map
* @return columns with data
*/
public ObservableMap<String, ObjectProperty<CSVValue>> getColumns() {
return columns;
}
/**
* stores the given value in the given column of this row
* @param column column name
* @param value the value to store
*/
public void addValue(String column, String value) {
CSVValue v = new CSVValue();
v.setValidator(validator);
v.setValue(value);
v.setColumn(column);
v.setRowNumber(rowNumber);
columns.put(column, new SimpleObjectProperty<>(v));
}
}

View File

@@ -0,0 +1,112 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.fx.table.model;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import ninja.javafx.smartcsv.validation.ValidationState;
import ninja.javafx.smartcsv.validation.Validator;
/**
* The csv value represents the value of a single cell.
* It also knows about the position (row and column)
* and if the value is valid based on the validator.
*/
public class CSVValue {
private Validator validator;
private int rowNumber;
private String column;
private StringProperty value = new SimpleStringProperty();
private ValidationState valid = new ValidationState();
/**
* single value of a cell
* @param validator the reference to the validator
*/
public void setValidator(Validator validator) {
this.validator = validator;
}
/**
* the row number this value is stored in
* @param row row number
*/
public void setRowNumber(int row) {
this.rowNumber = row;
}
/**
* the column this value is stored in
* @param column header name of the column
*/
public void setColumn(String column) {
this.column = column;
}
/**
* returns the real value
* @return the real value
*/
public String getValue() {
return value.get();
}
/**
* JavaFX property representation of the real value
* @return property of real value
*/
public StringProperty valueProperty() {
return value;
}
/**
* sets the real value
* @param value the real value
*/
public void setValue(String value) {
if (validator != null) {
valid = validator.isValid(column, value);
}
this.value.set(value);
}
/**
* returns if the value is valid to the rules of the validator
* @return
*/
public ValidationState getValid() {
return valid;
}
/**
* sets the state if a value is valid or not
* @param valid the validation state
*/
protected void setValid(ValidationState valid) {
this.valid = valid;
}
}

View File

@@ -0,0 +1,53 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import ninja.javafx.smartcsv.FileReader;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;
/**
* This class loads the constraints as json config
*/
@Service
public class ValidationFileReader implements FileReader {
private Config config;
@Override
public void read(File file) throws IOException {
config = ConfigFactory.parseFile(file);
}
public Validator getValidator() {
return new Validator(config);
}
}

View File

@@ -0,0 +1,51 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import java.io.StringWriter;
/**
* Created by Andreas on 28.11.2015.
*/
public class ValidationState {
private boolean valid = true;
private StringWriter messages = new StringWriter();
public void invalidate(String message) {
valid = false;
messages.append(message).append('\n');
}
public boolean isValid() {
return valid;
}
public String error() {
return messages.toString();
}
}

View File

@@ -0,0 +1,216 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import com.typesafe.config.Config;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import org.codehaus.groovy.control.CompilationFailedException;
import java.util.HashMap;
import java.util.Map;
import static org.apache.commons.validator.GenericValidator.*;
/**
* This class checks all the validations defined in the
* Config against a given value
*/
public class Validator {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// member variables
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private Config validationConfig;
private GroovyShell shell = new GroovyShell();
private Map<String, Script> scriptCache = new HashMap<>();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constructors
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* JSON configuration for this validator
* @param validationConfig
*/
public Validator(Config validationConfig) {
this.validationConfig = validationConfig;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// oublic methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* checks if the value is valid for the column configuration
* @param column the column name
* @param value the value to check
* @return ValidationState with information if valid and if not which error happened
*/
public ValidationState isValid(String column, String value) {
ValidationState result = new ValidationState();
if (validationConfig != null) {
Config columnConfig = getColumnConfig(column);
if (columnConfig != null) {
checkBlankOrNull(columnConfig, value, result);
if (value != null) {
checkRegularExpression(columnConfig, value, result);
checkAlphaNumeric(columnConfig, value, result);
checkDate(columnConfig, value, result);
checkMaxLength(columnConfig, value, result);
checkMinLength(columnConfig, value, result);
checkInteger(columnConfig, value, result);
checkGroovy(column, columnConfig, value, result);
}
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void checkGroovy(String column, Config columnConfig, String value, ValidationState result) {
String groovyScript = getString(columnConfig, "groovy");
if (groovyScript != null) {
Script script = scriptCache.get(column);
if (script == null) {
script = shell.parse(groovyScript);
scriptCache.put(column, script);
}
Binding binding = new Binding();
binding.setVariable("value", value);
script.setBinding(binding);
Object groovyResult = null;
try {
groovyResult = script.run();
} catch (CompilationFailedException e) {
result.invalidate("groovy script '"+groovyScript+"' throws exception: "+e.getMessage());
e.printStackTrace();
}
if (groovyResult == null) {
result.invalidate("groovy script '"+groovyScript+"' returns null");
}
if (!isScriptResultTrue(groovyResult)) {
result.invalidate(groovyResult.toString());
}
}
}
private boolean isScriptResultTrue(Object groovyResult) {
return groovyResult.equals(true) || groovyResult.toString().trim().toLowerCase().equals("true");
}
private void checkBlankOrNull(Config columnConfig, String value, ValidationState result) {
if (getBoolean(columnConfig, "not empty")) {
if (isBlankOrNull(value)) {
result.invalidate("should not be empty");
}
}
}
private void checkInteger(Config columnConfig, String value, ValidationState result) {
if (getBoolean(columnConfig, "integer")) {
if (!isInt(value)) {
result.invalidate("should be an integer");
}
}
}
private void checkMinLength(Config columnConfig, String value, ValidationState result) {
Integer minLength = getInteger(columnConfig, "minlength");
if (minLength != null) {
if (!minLength(value, minLength)) {
result.invalidate("has not min length of " + minLength);
}
}
}
private void checkMaxLength(Config columnConfig, String value, ValidationState result) {
Integer maxLength = getInteger(columnConfig, "maxlength");
if (maxLength != null) {
if (!maxLength(value, maxLength)) {
result.invalidate("has not max length of " + maxLength);
}
}
}
private void checkDate(Config columnConfig, String value, ValidationState result) {
String dateformat = getString(columnConfig, "date");
if (dateformat != null && !dateformat.trim().isEmpty()) {
if (!isDate(value, dateformat, true)) {
result.invalidate("is not a date of format " + dateformat);
}
}
}
private void checkAlphaNumeric(Config columnConfig, String value, ValidationState result) {
if (getBoolean(columnConfig, "alphanumeric")) {
if (!matchRegexp(value, "[0-9a-zA-Z]*")) {
result.invalidate("should not be alphanumeric");
}
}
}
private void checkRegularExpression(Config columnConfig, String value, ValidationState result) {
String regexp = getString(columnConfig, "regexp");
if (regexp != null && !regexp.trim().isEmpty()) {
if (!matchRegexp(value, regexp)) {
result.invalidate("does not match " + regexp);
}
}
}
private Config getColumnConfig(String column) {
return validationConfig.hasPath(column) ? validationConfig.getConfig(column) : null;
}
private String getString(Config columnConfig, String path) {
return columnConfig.hasPath(path) ? columnConfig.getString(path) : null;
}
private Integer getInteger(Config columnConfig, String path) {
return columnConfig.hasPath(path) ? columnConfig.getInt(path) : null;
}
private boolean getBoolean(Config columnConfig, String path) {
return columnConfig.hasPath(path) && columnConfig.getBoolean(path);
}
}