001package gwt.material.design.client.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 com.google.gwt.editor.client.Editor;
024import com.google.gwt.editor.client.EditorError;
025import com.google.gwt.event.dom.client.BlurEvent;
026import com.google.gwt.event.dom.client.BlurHandler;
027import com.google.gwt.event.logical.shared.ValueChangeEvent;
028import com.google.gwt.event.logical.shared.ValueChangeHandler;
029import com.google.gwt.event.shared.GwtEvent;
030import com.google.gwt.user.client.ui.HasValue;
031import com.google.gwt.user.client.ui.Widget;
032import com.google.web.bindery.event.shared.EventBus;
033import com.google.web.bindery.event.shared.HandlerRegistration;
034import com.google.web.bindery.event.shared.SimpleEventBus;
035import gwt.material.design.client.base.error.ErrorHandler;
036import gwt.material.design.client.base.validator.HasValidators;
037import gwt.material.design.client.base.validator.ValidationChangedEvent;
038import gwt.material.design.client.base.validator.ValidationChangedEvent.ValidationChangedHandler;
039import gwt.material.design.client.base.validator.Validator;
040import gwt.material.design.client.base.validator.ValidatorWrapper;
041
042import java.util.ArrayList;
043import java.util.List;
044import java.util.Set;
045import java.util.TreeSet;
046
047/**
048 * Default validator mixin. Contains all of the validation logic.
049 *
050 * @param <W> the generic type
051 * @param <V> the value type
052 * 
053 * @author Steven Jardine
054 */
055public class ValidatorMixin<W extends Widget & HasValue<V> & Editor<V>, V> implements HasValidators<V> {
056
057    protected ErrorHandler errorHandler;
058
059    private EventBus eventBus;
060
061    protected W inputWidget;
062
063    private Boolean valid = null;
064
065    private boolean validateOnBlur;
066
067    protected Set<ValidatorWrapper<V>> validators = new TreeSet<>();
068
069    /**
070     * Instantiates a new abstract validator mixin.
071     *
072     * @param inputWidget the input widget
073     * @param errorHandler the error handler
074     */
075    public ValidatorMixin(W inputWidget, ErrorHandler errorHandler) {
076        this.inputWidget = inputWidget;
077        this.errorHandler = errorHandler;
078        eventBus = new SimpleEventBus();
079
080        setupValueChangeValidation();
081    }
082
083    protected HandlerRegistration setupValueChangeValidation() {
084        return inputWidget.addHandler(new ValueChangeHandler<V>() {
085            @Override
086            public void onValueChange(ValueChangeEvent<V> event) {
087                validate(false);
088            }
089        }, ValueChangeEvent.getType());
090    }
091
092    @Override
093    public HandlerRegistration addValidationChangedHandler(ValidationChangedHandler handler) {
094        return eventBus.addHandler(ValidationChangedEvent.getType(), handler);
095    }
096
097    @Override
098    public void addValidator(Validator<V> validator) {
099        validators.add(new ValidatorWrapper<>(validator, validators.size()));
100    }
101
102    @Override
103    public void fireEvent(GwtEvent<?> event) {
104        eventBus.fireEvent(event);
105    }
106
107    /**
108     * @return the inputWidget
109     */
110    public W getInputWidget() {
111        return inputWidget;
112    }
113
114    @Override
115    public boolean isValidateOnBlur() {
116        return validateOnBlur;
117    }
118
119    @Override
120    public boolean removeValidator(Validator<V> validator) {
121        for (ValidatorWrapper<V> wrapper : validators) {
122            if (wrapper.getValidator().equals(validator)) { return validators.remove(wrapper); }
123        }
124        return false;
125    }
126
127    @Override
128    public void reset() {
129        if (errorHandler != null) {
130            errorHandler.clearErrors();
131        }
132    }
133
134    /**
135     * Sets the error handler.
136     *
137     * @param errorHandler the new error handler
138     */
139    public void setErrorHandler(ErrorHandler errorHandler) {
140        this.errorHandler = errorHandler;
141    }
142
143    @Override
144    public void setValidateOnBlur(boolean vob) {
145        validateOnBlur = vob;
146    }
147
148    @Override
149    public void setValidators(@SuppressWarnings("unchecked") Validator<V>... newValidators) {
150        validators.clear();
151        for (Validator<V> validator : newValidators) {
152            addValidator(validator);
153        }
154    }
155
156    @Override
157    public boolean validate() {
158        return validate(true);
159    }
160
161    /** {@inheritDoc} */
162    @Override
163    public boolean validate(boolean show) {
164        Boolean oldValid = valid;
165        valid = true;
166        if (errorHandler != null && !validators.isEmpty()) {
167            List<EditorError> errors = new ArrayList<EditorError>();
168            for (ValidatorWrapper<V> wrapper : validators) {
169                Validator<V> validator = wrapper.getValidator();
170                List<EditorError> result = validator.validate(inputWidget, inputWidget.getValue());
171                if (result != null && !result.isEmpty()) {
172                    errors.addAll(result);
173                    valid = false;
174                }
175            }
176            if (show) {
177                if (errors.size() > 0) {
178                    errorHandler.showErrors(errors);
179                } else {
180                    errorHandler.clearErrors();
181                }
182            }
183        }
184        if (valid != oldValid) {
185            eventBus.fireEvent(new ValidationChangedEvent(valid));
186        }
187        return valid;
188    }
189}