001package org.gwtbootstrap3.client.ui.base.mixin;
002
003/*
004 * #%L
005 * GwtBootstrap3
006 * %%
007 * Copyright (C) 2013 - 2015 GwtBootstrap3
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import java.util.ArrayList;
024import java.util.List;
025import java.util.Set;
026import java.util.TreeSet;
027
028import org.gwtbootstrap3.client.ui.form.error.ErrorHandler;
029import org.gwtbootstrap3.client.ui.form.validator.HasValidators;
030import org.gwtbootstrap3.client.ui.form.validator.ValidationChangedEvent;
031import org.gwtbootstrap3.client.ui.form.validator.ValidationChangedEvent.ValidationChangedHandler;
032import org.gwtbootstrap3.client.ui.form.validator.Validator;
033import org.gwtbootstrap3.client.ui.form.validator.ValidatorWrapper;
034
035import com.google.gwt.editor.client.Editor;
036import com.google.gwt.editor.client.EditorError;
037import com.google.gwt.event.dom.client.BlurEvent;
038import com.google.gwt.event.dom.client.BlurHandler;
039import com.google.gwt.event.logical.shared.ValueChangeEvent;
040import com.google.gwt.event.logical.shared.ValueChangeHandler;
041import com.google.gwt.event.shared.GwtEvent;
042import com.google.gwt.user.client.ui.HasValue;
043import com.google.gwt.user.client.ui.Widget;
044import com.google.web.bindery.event.shared.EventBus;
045import com.google.web.bindery.event.shared.HandlerRegistration;
046import com.google.web.bindery.event.shared.SimpleEventBus;
047
048/**
049 * Abstract validator mixin. Contains all of the validation logic.
050 *
051 * @param <W> the generic type
052 * @param <V> the value type
053 * 
054 * @author Steven Jardine
055 */
056public class DefaultValidatorMixin<W extends Widget & HasValue<V> & Editor<V>, V> implements HasValidators<V> {
057
058    protected ErrorHandler errorHandler;
059
060    private EventBus eventBus;
061
062    private W inputWidget;
063
064    private Boolean valid = null;
065
066    private boolean validateOnBlur;
067
068    protected Set<ValidatorWrapper<V>> validators = new TreeSet<ValidatorWrapper<V>>();
069
070    /**
071     * Instantiates a new abstract validator mixin.
072     *
073     * @param inputWidget the input widget
074     * @param errorHandler the error handler
075     */
076    public DefaultValidatorMixin(W inputWidget, ErrorHandler errorHandler) {
077        this.inputWidget = inputWidget;
078        this.errorHandler = errorHandler;
079        eventBus = new SimpleEventBus();
080
081        setupBlurValidation();
082        setupValueChangeValidation();
083    }
084
085    protected HandlerRegistration setupBlurValidation() {
086        return inputWidget.addDomHandler(new BlurHandler() {
087            @Override
088            public void onBlur(BlurEvent event) {
089                validate(validateOnBlur);
090            }
091        }, BlurEvent.getType());
092    }
093
094    protected HandlerRegistration setupValueChangeValidation() {
095        return inputWidget.addHandler(new ValueChangeHandler<V>() {
096            @Override
097            public void onValueChange(ValueChangeEvent<V> event) {
098                validate(false);
099            }
100        }, ValueChangeEvent.getType());
101    }
102
103    @Override
104    public HandlerRegistration addValidationChangedHandler(ValidationChangedHandler handler) {
105        return eventBus.addHandler(ValidationChangedEvent.getType(), handler);
106    }
107
108    /** {@inheritDoc} */
109    @Override
110    public void addValidator(Validator<V> validator) {
111        validators.add(new ValidatorWrapper<V>(validator, validators.size()));
112    }
113
114    @Override
115    public void fireEvent(GwtEvent<?> event) {
116        eventBus.fireEvent(event);
117    }
118
119    /**
120     * @return the inputWidget
121     */
122    public W getInputWidget() {
123        return inputWidget;
124    }
125
126    /** {@inheritDoc} */
127    @Override
128    public boolean getValidateOnBlur() {
129        return validateOnBlur;
130    }
131
132    /** {@inheritDoc} */
133    @Override
134    public boolean removeValidator(Validator<V> validator) {
135        for (ValidatorWrapper<V> wrapper : validators) {
136            if (wrapper.getValidator().equals(validator)) { return validators.remove(wrapper); }
137        }
138        return false;
139    }
140
141    /** {@inheritDoc} */
142    @Override
143    public void reset() {
144        if (errorHandler != null) {
145            errorHandler.clearErrors();
146        }
147    }
148
149    /**
150     * Sets the error handler.
151     *
152     * @param errorHandler the new error handler
153     */
154    public void setErrorHandler(ErrorHandler errorHandler) {
155        this.errorHandler = errorHandler;
156    }
157
158    /** {@inheritDoc} */
159    @Override
160    public void setValidateOnBlur(boolean vob) {
161        validateOnBlur = vob;
162    }
163
164    /** {@inheritDoc} */
165    @Override
166    public void setValidators(@SuppressWarnings("unchecked") Validator<V>... newValidators) {
167        validators.clear();
168        for (Validator<V> validator : newValidators) {
169            addValidator(validator);
170        }
171    }
172
173    /** {@inheritDoc} */
174    @Override
175    public boolean validate() {
176        return validate(true);
177    }
178
179    /** {@inheritDoc} */
180    @Override
181    public boolean validate(boolean show) {
182        Boolean oldValid = valid;
183        valid = true;
184        if (errorHandler != null && !validators.isEmpty()) {
185            List<EditorError> errors = new ArrayList<EditorError>();
186            for (ValidatorWrapper<V> wrapper : validators) {
187                Validator<V> validator = wrapper.getValidator();
188                List<EditorError> result = validator.validate(inputWidget, inputWidget.getValue());
189                if (result != null && !result.isEmpty()) {
190                    errors.addAll(result);
191                    valid = false;
192                }
193            }
194            if (show) {
195                if (errors.size() > 0) {
196                    errorHandler.showErrors(errors);
197                } else {
198                    errorHandler.clearErrors();
199                }
200            }
201        }
202        if (valid != oldValid) {
203            eventBus.fireEvent(new ValidationChangedEvent(valid));
204        }
205        return valid;
206    }
207
208}