001package org.gwtbootstrap3.client.ui.form.error;
002
003/*
004 * #%L
005 * GwtBootstrap3
006 * %%
007 * Copyright (C) 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.List;
024
025import org.gwtbootstrap3.client.ui.HelpBlock;
026import org.gwtbootstrap3.client.ui.base.HasValidationState;
027import org.gwtbootstrap3.client.ui.base.ValueBoxBase;
028import org.gwtbootstrap3.client.ui.constants.ValidationState;
029
030import com.google.gwt.editor.client.EditorError;
031import com.google.gwt.event.logical.shared.AttachEvent;
032import com.google.gwt.event.logical.shared.AttachEvent.Handler;
033import com.google.gwt.user.client.ui.HasWidgets;
034import com.google.gwt.user.client.ui.Widget;
035
036/**
037 * This is the default {@link ErrorHandler} implementation. The assumption is that every {@link ValueBoxBase}
038 * instance will have a {@link HasValidationState} parent. If there is a {@link HelpBlock} that is a child of
039 * the {@link HasValidationState} parent then error messages will be displayed in the {@link HelpBlock}.
040 * 
041 * Example:
042 * 
043 * <pre>{@code
044 * <b:FormGroup> 
045 *      <b:FormLabel for="username">User</b:FormLabel> 
046 *      <b:TextBox b:id="username" ui:field="username" /> 
047 *      <b:HelpBlock iconType="EXCLAMATION" /> 
048 * </b:FormGroup>
049 * }</pre>
050 * 
051 * @author Steven Jardine
052 */
053public class DefaultErrorHandler implements ErrorHandler {
054
055    private boolean initialized = false;
056
057    private final Widget inputWidget;
058
059    private HelpBlock validationStateHelpBlock = null;
060
061    private HasValidationState validationStateParent = null;
062
063    /**
064     * Default error handler.
065     *
066     * @param parent the parent of this error handler.
067     */
068    public DefaultErrorHandler(Widget widget) {
069        super();
070        assert widget != null;
071        this.inputWidget = widget;
072        this.inputWidget.addAttachHandler(new Handler() {
073            @Override
074            public void onAttachOrDetach(AttachEvent event) {
075                init();
076            }
077        });
078    }
079
080    /** {@inheritDoc} */
081    @Override
082    public void cleanup() {
083    }
084
085    /** {@inheritDoc} */
086    @Override
087    public void clearErrors() {
088        if (validationStateParent == null) { return; }
089        validationStateParent.setValidationState(ValidationState.NONE);
090        if (validationStateHelpBlock != null) { validationStateHelpBlock.clearError(); }
091    }
092
093    /**
094     * Find the sibling {@link HelpBlock}.
095     *
096     * @param widget the {@link Widget} to search.
097     * @return the found {@link HelpBlock} of null if not found.
098     */
099    private HelpBlock findHelpBlock(Widget widget) {
100        if (widget instanceof HelpBlock) { return (HelpBlock) widget; }
101        // Try and find the HelpBlock in the children of the given widget.
102        if (widget instanceof HasWidgets) {
103            for (Widget w : (HasWidgets) widget) {
104                if (w instanceof HelpBlock) { return (HelpBlock) w; }
105            }
106        }
107        if (!(widget instanceof HasValidationState)) {
108            // Try and find the HelpBlock in the parent of widget.
109            return findHelpBlock(widget.getParent());
110        }
111        return null;
112    }
113
114    /**
115     * Initialize the instance. We find the parent {@link HasValidationState} and sibling {@link HelpBlock}
116     * only 1 time on initialization.
117     */
118    public void init() {
119        if (initialized) { return; }
120        Widget parent = inputWidget.getParent();
121        while (parent != null && !parent.getClass().getName().equals("com.google.gwt.user.client.ui.Widget")) {
122            if (parent instanceof HasValidationState) {
123                validationStateParent = (HasValidationState) parent;
124                validationStateHelpBlock = findHelpBlock(inputWidget);
125                break;
126            }
127            parent = parent.getParent();
128        }
129        if (inputWidget.isAttached() || validationStateParent != null) {
130            initialized = true;
131        }
132    }
133
134    /** {@inheritDoc} */
135    @Override
136    public void showErrors(List<EditorError> errors) {
137        init();
138        // clearErrors();
139        String errorMsg = "";
140        if (validationStateParent != null) {
141            validationStateParent.setValidationState(errors.size() <= 0 ? ValidationState.NONE : ValidationState.ERROR);
142            for (int index = 0; index < errors.size(); index++) {
143                errorMsg = errors.get(0).getMessage();
144                if (index + 1 < errors.size()) { errorMsg += "; "; }
145            }
146        }
147        if (validationStateHelpBlock != null) {
148            validationStateHelpBlock.setError(errorMsg);
149        }
150    }
151
152}