/* * Copyright [2014] [Christian Loehnert, krampenschiesser@gmail.com] * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.ks.validation; import de.ks.activity.context.ActivityScoped; import de.ks.activity.context.ActivityStore; import de.ks.validation.validators.BeanValidationValidator; import de.ks.validation.validators.ValidatorChain; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.adapter.JavaBeanProperty; import javafx.scene.Node; import javafx.scene.control.Control; import org.controlsfx.validation.ValidationResult; import org.controlsfx.validation.ValidationSupport; import org.controlsfx.validation.decoration.CompoundValidationDecoration; import org.controlsfx.validation.decoration.StyleClassValidationDecoration; import org.controlsfx.validation.decoration.ValidationDecoration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.validation.Validator; import javax.validation.metadata.BeanDescriptor; import javax.validation.metadata.PropertyDescriptor; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.Set; @ActivityScoped public class ValidationRegistry { private static final Logger log = LoggerFactory.getLogger(ValidationRegistry.class); protected final ValidationSupport validationSupport = new ValidationSupport(); protected final Map<String, Control> registeredControls = new HashMap<>(); protected final Map<Control, ValidatorChain<?>> registeredValidators = new HashMap<>(); protected final SimpleBooleanProperty invalid = new SimpleBooleanProperty(false); @Inject Validator validator; @Inject ActivityStore store; public ValidationRegistry() { ValidationDecoration iconDecorator = new CustomValidationDecoration(); ValidationDecoration cssDecorator = new StyleClassValidationDecoration(); ValidationDecoration compoundDecorator = new CompoundValidationDecoration(cssDecorator, iconDecorator); validationSupport.setValidationDecorator(compoundDecorator); } @PostConstruct public void init() { validationSupport.invalidProperty().addListener((p, o, n) -> { invalid.set(n || store.isLoading()); log.trace("Validation is {}", invalid.get() ? "Invalid" : "valid"); }); store.loadingProperty().addListener((p, o, n) -> { Boolean isInvalid = validationSupport.isInvalid(); if (isInvalid == null) { invalid.set(n); } else { invalid.set(n || isInvalid); } log.trace("Validation is {}", invalid.get() ? "Invalid" : "valid"); }); } public void addProperty(JavaBeanProperty<?> property, Node node) { Object model = store.getModel(); if (node instanceof Control) { Control control = (Control) node; Class<?> modelClass = model.getClass(); String propertyName = property.getName(); BeanDescriptor constraints = validator.getConstraintsForClass(modelClass); PropertyDescriptor constraintsForProperty = constraints == null ? null : constraints.getConstraintsForProperty(propertyName); if (constraintsForProperty != null && constraintsForProperty.hasConstraints()) { registeredControls.put(propertyName, control); registerBeanValidationValidator(control, modelClass, propertyName); log.debug("Registered BeanValidation validator for property {} on control {}", propertyName, control); } } } public ValidationResult getValidationResult() { return validationSupport.getValidationResult(); } public boolean isInvalid() { return invalid.get(); } public boolean isValid() { return !invalid.get(); } public ReadOnlyBooleanProperty invalidProperty() { return invalid; } public void registerBeanValidationValidator(Control control, Class<?> clazz, String propertyName) { registerValidator(control, true, new BeanValidationValidator(clazz, validator, propertyName)); } public <T> boolean registerValidator(Control control, boolean required, org.controlsfx.validation.Validator<T> validator) { @SuppressWarnings("unchecked") ValidatorChain<T> validatorChain = (ValidatorChain<T>) this.registeredValidators.computeIfAbsent(control, c -> { ValidatorChain<Object> retval = new ValidatorChain<>(); validationSupport.registerValidator(control, required, retval); return retval; }); validatorChain.addValidator(validator); return true; } public <T> boolean registerValidator(Control control, org.controlsfx.validation.Validator<T> validator) { return registerValidator(control, true, validator); } public Optional<org.controlsfx.validation.ValidationMessage> getHighestMessage(Control target) { return validationSupport.getHighestMessage(target); } public Set<Control> getRegisteredControls() { return validationSupport.getRegisteredControls(); } protected ValidationSupport getValidationSupport() { return validationSupport; } }