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.
*
* 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