diff --git a/mvvmfx-validation/src/main/java/de/saxsys/mvvmfx/utils/validation/visualization/ControlsFxVisualizer.java b/mvvmfx-validation/src/main/java/de/saxsys/mvvmfx/utils/validation/visualization/ControlsFxVisualizer.java index 2533c7384..39e50c736 100644 --- a/mvvmfx-validation/src/main/java/de/saxsys/mvvmfx/utils/validation/visualization/ControlsFxVisualizer.java +++ b/mvvmfx-validation/src/main/java/de/saxsys/mvvmfx/utils/validation/visualization/ControlsFxVisualizer.java @@ -32,14 +32,14 @@ * this visualization you have to add the ControlsFX library to your classpath, otherwise you will get * {@link NoClassDefFoundError}s and {@link ClassNotFoundException}s. If you are using a build management system like * maven or gradle you simply have to add the library as dependency. - * - * + * + * * @author manuel.mauky */ public class ControlsFxVisualizer extends ValidationVisualizerBase { - + private ValidationDecoration decoration = new GraphicValidationDecoration(); - + /** * Define a custom ControlsFX {@link ValidationVisualizer} that is used to visualize the validation results. *

@@ -48,24 +48,24 @@ public class ControlsFxVisualizer extends ValidationVisualizerBase { public void setDecoration(ValidationDecoration decoration) { this.decoration = decoration; } - - + + @Override - void applyRequiredVisualization(Control control, boolean required) { + protected void applyRequiredVisualization(Control control, boolean required) { ValidationSupport.setRequired(control, required); if (required) { decoration.applyRequiredDecoration(control); } } - + @Override - void applyVisualization(Control control, Optional messageOptional, boolean required) { - + protected void applyVisualization(Control control, Optional messageOptional, boolean required) { + if (messageOptional.isPresent()) { final ValidationMessage message = messageOptional.get(); - + decoration.removeDecorations(control); - + if (Severity.ERROR.equals(message.getSeverity())) { decoration.applyValidationDecoration(org.controlsfx.validation.ValidationMessage.error(control, message.getMessage())); @@ -73,14 +73,14 @@ void applyVisualization(Control control, Optional messageOpti decoration.applyValidationDecoration(org.controlsfx.validation.ValidationMessage.warning(control, message.getMessage())); } - + } else { decoration.removeDecorations(control); } - + if (required) { decoration.applyRequiredDecoration(control); } } - + } diff --git a/mvvmfx-validation/src/main/java/de/saxsys/mvvmfx/utils/validation/visualization/ValidationVisualizerBase.java b/mvvmfx-validation/src/main/java/de/saxsys/mvvmfx/utils/validation/visualization/ValidationVisualizerBase.java index 4da22dc15..6ccfca6a6 100644 --- a/mvvmfx-validation/src/main/java/de/saxsys/mvvmfx/utils/validation/visualization/ValidationVisualizerBase.java +++ b/mvvmfx-validation/src/main/java/de/saxsys/mvvmfx/utils/validation/visualization/ValidationVisualizerBase.java @@ -33,12 +33,12 @@ *

* This base class takes care for the handling of the {@link ValidationStatus} and the reaction to it's changing message * lists. - * + * * @author manuel.mauky */ public abstract class ValidationVisualizerBase implements ValidationVisualizer { - - + + @Override public void initVisualization(final ValidationStatus result, final Control control, boolean required) { Platform.runLater(() -> { @@ -56,19 +56,19 @@ public void initVisualization(final ValidationStatus result, final Control contr }); }); } - + /** * Apply a visualization to the given control that indicates that it is a mandatory field. *

* This method is called when the validator is initialized. - * + * * @param control * the controls that has to be decorated. * @param required * a boolean indicating whether the given control is mandatory or not. */ - abstract void applyRequiredVisualization(Control control, boolean required); - + protected abstract void applyRequiredVisualization(Control control, boolean required); + /** * Apply a visualization to the given control that shows a validation message. *

@@ -81,8 +81,8 @@ public void initVisualization(final ValidationStatus result, final Control contr *

* The given boolean parameter indicates whether this controls is mandatory or not. It can be used if a violation * for a mandatory field should be visualized differently than a non-mandatory field. - * - * + * + * * @param control * the control that will be decorated. * @param messageOptional @@ -91,6 +91,6 @@ public void initVisualization(final ValidationStatus result, final Control contr * @param required * a boolean flag indicating whether this control is mandatory or not. */ - abstract void applyVisualization(Control control, Optional messageOptional, boolean required); - + protected abstract void applyVisualization(Control control, Optional messageOptional, boolean required); + } diff --git a/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizer.java b/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizer.java new file mode 100644 index 000000000..985be4573 --- /dev/null +++ b/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizer.java @@ -0,0 +1,44 @@ +package de.saxsys.mvvmfx.utils.validation.cssvisualizer; + +import de.saxsys.mvvmfx.utils.validation.ValidationMessage; +import de.saxsys.mvvmfx.utils.validation.visualization.ValidationVisualizerBase; + +import java.util.List; +import java.util.Optional; + +import javafx.scene.control.Control; + +public class CssVisualizer extends ValidationVisualizerBase { + + private final String errorStyleClass; + private final String validStyleClass; + private final String requiredStyleClass; + + public CssVisualizer(String errorStyleClass, String validStyleClass, String requiredStyleClass) { + this.errorStyleClass = errorStyleClass; + this.validStyleClass = validStyleClass; + this.requiredStyleClass = requiredStyleClass; + } + + @Override + protected void applyRequiredVisualization(Control control, boolean required) { + addIfAbsent(control.getStyleClass(), requiredStyleClass); + } + + @Override + public void applyVisualization(Control control, Optional messageOptional, boolean required) { + if (messageOptional.isPresent()) { + control.getStyleClass().remove(validStyleClass); + addIfAbsent(control.getStyleClass(), errorStyleClass); + } else { + control.getStyleClass().remove(errorStyleClass); + addIfAbsent(control.getStyleClass(), validStyleClass); + } + } + + private static void addIfAbsent(List list, T element) { + if (!list.contains(element)) { + list.add(element); + } + } +} diff --git a/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizerExampleApp.java b/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizerExampleApp.java new file mode 100644 index 000000000..b104a367b --- /dev/null +++ b/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizerExampleApp.java @@ -0,0 +1,23 @@ +package de.saxsys.mvvmfx.utils.validation.cssvisualizer; + +import de.saxsys.mvvmfx.FluentViewLoader; +import javafx.application.Application; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Stage; + +public class CssVisualizerExampleApp extends Application { + + public static void main(String[] args) { + launch(args); + } + + @Override + public void start(Stage primaryStage) throws Exception { + + Parent parent = FluentViewLoader.fxmlView(CssVisualizerView.class).load().getView(); + + primaryStage.setScene(new Scene(parent)); + primaryStage.show(); + } +} diff --git a/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizerView.java b/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizerView.java new file mode 100644 index 000000000..c5dbe9143 --- /dev/null +++ b/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizerView.java @@ -0,0 +1,24 @@ +package de.saxsys.mvvmfx.utils.validation.cssvisualizer; + +import de.saxsys.mvvmfx.FxmlView; +import de.saxsys.mvvmfx.InjectViewModel; +import de.saxsys.mvvmfx.utils.validation.visualization.ValidationVisualizer; +import javafx.fxml.FXML; +import javafx.scene.control.TextField; + +public class CssVisualizerView implements FxmlView { + + @FXML + private TextField email; + + @InjectViewModel + private CssVisualizerViewModel viewModel; + + private ValidationVisualizer visualizer = new CssVisualizer("error", "valid", "required"); + + public void initialize() { + email.textProperty().bindBidirectional(viewModel.emailAddressProperty()); + + visualizer.initVisualization(viewModel.getValidationStatus(), email, true); + } +} diff --git a/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizerViewModel.java b/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizerViewModel.java new file mode 100644 index 000000000..d3aa5632f --- /dev/null +++ b/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizerViewModel.java @@ -0,0 +1,36 @@ +package de.saxsys.mvvmfx.utils.validation.cssvisualizer; + +import de.saxsys.mvvmfx.ViewModel; +import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator; +import de.saxsys.mvvmfx.utils.validation.ValidationMessage; +import de.saxsys.mvvmfx.utils.validation.ValidationStatus; +import de.saxsys.mvvmfx.utils.validation.Validator; + +import java.util.function.Function; +import java.util.regex.Pattern; + +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +public class CssVisualizerViewModel implements ViewModel { + private static final Pattern EMAIL_REGEX = Pattern + .compile("^$|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"); + + private StringProperty emailAddress = new SimpleStringProperty(""); + + private Validator validator = new FunctionBasedValidator(emailAddress, input -> { + if (input == null || input.trim().isEmpty() || !EMAIL_REGEX.matcher(input).matches()) { + return ValidationMessage.error("Invalid EMail address"); + } else { + return null; + } + }); + + public ValidationStatus getValidationStatus() { + return validator.getValidationStatus(); + } + + public StringProperty emailAddressProperty() { + return emailAddress; + } +} diff --git a/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/package-info.java b/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/package-info.java new file mode 100644 index 000000000..d63cd85fe --- /dev/null +++ b/mvvmfx-validation/src/test/java/de/saxsys/mvvmfx/utils/validation/cssvisualizer/package-info.java @@ -0,0 +1,5 @@ +/** + * This package contains an example for a simple custom visualizer that uses CSS styling. It's not intended to be an + * official visualizer but just a starting point for people to implement their own visualizers. + */ +package de.saxsys.mvvmfx.utils.validation.cssvisualizer; \ No newline at end of file diff --git a/mvvmfx-validation/src/test/resources/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizerView.fxml b/mvvmfx-validation/src/test/resources/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizerView.fxml new file mode 100644 index 000000000..e71730840 --- /dev/null +++ b/mvvmfx-validation/src/test/resources/de/saxsys/mvvmfx/utils/validation/cssvisualizer/CssVisualizerView.fxml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/mvvmfx-validation/src/test/resources/de/saxsys/mvvmfx/utils/validation/cssvisualizer/style.css b/mvvmfx-validation/src/test/resources/de/saxsys/mvvmfx/utils/validation/cssvisualizer/style.css new file mode 100644 index 000000000..cf6f64916 --- /dev/null +++ b/mvvmfx-validation/src/test/resources/de/saxsys/mvvmfx/utils/validation/cssvisualizer/style.css @@ -0,0 +1,12 @@ + +.error { + -fx-border-color: red; +} + +.valid { + -fx-border-color: green; +} + +.required { + -fx-background-color: yellow; +} \ No newline at end of file