package fr.openwide.core.wicket.more.markup.html.form.validation; import java.util.Collection; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.FormComponent; import org.apache.wicket.markup.html.form.validation.AbstractFormValidator; import org.apache.wicket.util.string.Strings; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; public class OneRequiredFormValidator extends AbstractFormValidator { private static final long serialVersionUID = -7019352590059451557L; protected Collection<FormComponent<?>> requiredFormComponents; protected OneRequiredMode mode = OneRequiredMode.ONE_OR_MORE; protected OneRequiredFormValidator() { // Permet d'hériter de ce validator pour des cas spécifiques quand on ne dispose pas des champs tout de suite. } public OneRequiredFormValidator(FormComponent<?> first, FormComponent<?> second, FormComponent<?> ... rest) { this.requiredFormComponents = ImmutableList.<FormComponent<?>>builder().add(first, second).add(rest).build(); } public OneRequiredFormValidator setMode(OneRequiredMode mode) { this.mode = mode; return this; } @Override public FormComponent<?>[] getDependentFormComponents() { return Iterables.toArray( Iterables.concat(requiredFormComponents, getAdditionalDependentFormComponents()), FormComponent.class ); } protected Iterable<? extends FormComponent<?>> getAdditionalDependentFormComponents() { return ImmutableList.of(); } @Override public void validate(Form<?> form) { if (isEnabled(form)) { switch (mode) { case ONE_ONLY: boolean oneFilled = false; for (FormComponent<?> formComponent : requiredFormComponents) { if (checkRequired(formComponent)) { if (oneFilled) { onError(form); break; } else { oneFilled = true; } } } if (!oneFilled) { onError(form); } break; case ONE_OR_MORE: for (FormComponent<?> formComponent : requiredFormComponents) { if (checkRequired(formComponent)) { return; } } onError(form); break; } } } protected void onError(Form<?> form) { Joiner labelJoiner = Joiner.on(form.getString("common.validator.oneRequired.labels.separator")); String labels = labelJoiner.join(Iterables.transform(requiredFormComponents, new Function<FormComponent<?>, String>() { @Override public String apply(FormComponent<?> input) { return input.getLabel().getObject(); } })); if (mode == OneRequiredMode.ONE_ONLY) { error(requiredFormComponents.iterator().next(), "common.validator.oneRequired.oneOnly", ImmutableMap.<String, Object>of("labels", labels)); } else if (mode == OneRequiredMode.ONE_OR_MORE) { error(requiredFormComponents.iterator().next(), "common.validator.oneRequired.oneOrMore", ImmutableMap.<String, Object>of("labels", labels)); } else { error(requiredFormComponents.iterator().next(), "common.error"); } } /** * Code copied from FormComponent#checkRequired, which is unfortunately useless as long as FormComponent#required is false. */ protected boolean checkRequired(FormComponent<?> formComponent) { final String input = formComponent.getInput(); // when null, check whether this is natural for that component, or // whether - as is the case with text fields - this can only happen // when the component was disabled if (input == null && !formComponent.isInputNullable() && !formComponent.isEnabledInHierarchy()) { // this value must have come from a disabled field // do not perform validation return true; } // peform validation by looking whether the value is null or empty return !Strings.isEmpty(input); } public enum OneRequiredMode { ONE_OR_MORE, ONE_ONLY } }