001/*
002 * #%L
003 * GwtMaterial
004 * %%
005 * Copyright (C) 2015 - 2017 GwtMaterialDesign
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 * 
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 * 
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package gwt.material.design.client.base;
021
022import com.google.gwt.dom.client.Element;
023import com.google.gwt.editor.client.EditorError;
024import com.google.gwt.editor.client.HasEditorErrors;
025import com.google.gwt.editor.client.LeafValueEditor;
026import com.google.gwt.event.logical.shared.ValueChangeEvent;
027import com.google.gwt.event.logical.shared.ValueChangeHandler;
028import com.google.gwt.event.shared.HandlerRegistration;
029import com.google.gwt.user.client.ui.HasValue;
030import gwt.material.design.client.base.error.ErrorHandler;
031import gwt.material.design.client.base.error.ErrorHandlerType;
032import gwt.material.design.client.base.error.HasErrorHandler;
033import gwt.material.design.client.base.mixin.ErrorHandlerMixin;
034import gwt.material.design.client.base.mixin.ErrorMixin;
035import gwt.material.design.client.base.mixin.ValidatorMixin;
036import gwt.material.design.client.base.validator.BlankValidator;
037import gwt.material.design.client.base.validator.HasValidators;
038import gwt.material.design.client.base.validator.ValidationChangedEvent;
039import gwt.material.design.client.base.validator.Validator;
040
041import java.util.List;
042
043public abstract class AbstractValueWidget<V> extends MaterialWidget implements HasValue<V>, LeafValueEditor<V>,
044        HasEditorErrors<V>, HasErrorHandler, HasError, HasValidators<V> {
045
046    private boolean allowBlank = true;
047    private BlankValidator<V> blankValidator;
048    private ValidatorMixin<AbstractValueWidget<V>, V> validatorMixin;
049    private ErrorMixin<AbstractValueWidget, ?> errorMixin;
050    private ErrorHandlerMixin<V> errorHandlerMixin;
051
052    public AbstractValueWidget(Element element) {
053        super(element);
054    }
055
056    public AbstractValueWidget(Element element, String... initialClass) {
057        super(element, initialClass);
058    }
059
060    @Override
061    public void setValue(V value) {
062        setValue(value, false);
063    }
064
065    @Override
066    public void setValue(V value, boolean fireEvents) {
067        if (fireEvents) {
068            ValueChangeEvent.fire(this, value);
069        }
070    }
071
072    public void setValue(V value, boolean fireEvents, boolean reload) {
073        setValue(value, fireEvents);
074
075        if (this instanceof HasReload) {
076            if (reload) {
077                ((HasReload)this).reload();
078            }
079        }
080    }
081
082    @Override
083    public void setError(String error) {
084        getErrorMixin().setError(error);
085    }
086
087    @Override
088    public void setSuccess(String success) {
089        getErrorMixin().setSuccess(success);
090    }
091
092    @Override
093    public void setHelperText(String helperText) {
094        getErrorMixin().setHelperText(helperText);
095    }
096
097    @Override
098    public void clearErrorOrSuccess() {
099        getErrorMixin().clearErrorOrSuccess();
100    }
101
102    @Override
103    public void showErrors(List<EditorError> errors) {
104        getErrorHandlerMixin().showErrors(errors);
105    }
106
107    @Override
108    public ErrorHandler getErrorHandler() {
109        return getErrorHandlerMixin().getErrorHandler();
110    }
111
112    @Override
113    public void setErrorHandler(ErrorHandler errorHandler) {
114        getErrorHandlerMixin().setErrorHandler(errorHandler);
115    }
116
117    @Override
118    public ErrorHandlerType getErrorHandlerType() {
119        return getErrorHandlerMixin().getErrorHandlerType();
120    }
121
122    @Override
123    public void setErrorHandlerType(ErrorHandlerType errorHandlerType) {
124        getErrorHandlerMixin().setErrorHandlerType(errorHandlerType);
125    }
126
127    @Override
128    public void addValidator(Validator<V> validator) {
129        getValidatorMixin().addValidator(validator);
130    }
131
132    @Override
133    public boolean isValidateOnBlur() {
134        return getValidatorMixin().isValidateOnBlur();
135    }
136
137    @Override
138    public boolean removeValidator(Validator<V> validator) {
139        return getValidatorMixin().removeValidator(validator);
140    }
141
142    @Override
143    public void reset() {
144        getValidatorMixin().reset();
145    }
146
147    @Override
148    public void setValidateOnBlur(boolean validateOnBlur) {
149        getValidatorMixin().setValidateOnBlur(validateOnBlur);
150        setupBlurValidation();
151    }
152
153    @Override
154    public void setValidators(@SuppressWarnings("unchecked") Validator<V>... validators) {
155        getValidatorMixin().setValidators(validators);
156    }
157
158    @Override
159    public boolean validate() {
160        return getValidatorMixin().validate();
161    }
162
163    @Override
164    public boolean validate(boolean show) {
165        return getValidatorMixin().validate(show);
166    }
167
168    /**
169     * Enable or disable the default blank validator.
170     */
171    public void setAllowBlank(boolean allowBlank) {
172        this.allowBlank = allowBlank;
173
174        // Setup the allow blank validation
175        if (!allowBlank) {
176            if (blankValidator == null) {
177                blankValidator = createBlankValidator();
178            }
179            setupBlurValidation();
180            addValidator(blankValidator);
181        } else {
182            removeValidator(blankValidator);
183        }
184    }
185
186    /**
187     * Will this widget allow blank values upon validation.
188     */
189    public boolean isAllowBlank() {
190        return allowBlank;
191    }
192
193    /**
194     * Hook for custom blank validators.
195     *
196     * @return the blank validatorMixin
197     */
198    protected BlankValidator<V> createBlankValidator() {
199        return new BlankValidator<>();
200    }
201
202    protected void setupBlurValidation() {
203        final AbstractValueWidget inputWidget = getValidatorMixin().getInputWidget();
204        if (!inputWidget.isAttached()) {
205            registerHandler(inputWidget.addAttachHandler(attachEvent -> registerHandler(inputWidget.addBlurHandler(blurEvent -> validate(isValidateOnBlur())))));
206        } else {
207            registerHandler(inputWidget.addBlurHandler(blurEvent -> validate(isValidateOnBlur())));
208        }
209    }
210
211    @Override
212    public HandlerRegistration addValidationChangedHandler(ValidationChangedEvent.ValidationChangedHandler handler) {
213        return getValidatorMixin().addValidationChangedHandler(handler);
214    }
215
216    @Override
217    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<V> handler) {
218        return addHandler(handler, ValueChangeEvent.getType());
219    }
220
221    protected ValidatorMixin<AbstractValueWidget<V>, V> getValidatorMixin() {
222        if (validatorMixin == null) {
223            validatorMixin = new ValidatorMixin<>(this, getErrorHandler());
224        }
225        return validatorMixin;
226    }
227
228    protected ErrorMixin<AbstractValueWidget, ?> getErrorMixin() {
229        if (errorMixin == null) {
230            errorMixin = new ErrorMixin<>(this);
231        }
232        return errorMixin;
233    }
234
235    protected ErrorHandlerMixin<V> getErrorHandlerMixin() {
236        if (errorHandlerMixin == null) {
237            errorHandlerMixin = new ErrorHandlerMixin<>(this);
238        }
239        return errorHandlerMixin;
240    }
241}