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