001    package 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    
023    import java.util.List;
024    
025    import org.gwtbootstrap3.client.ui.HelpBlock;
026    import org.gwtbootstrap3.client.ui.base.HasValidationState;
027    import org.gwtbootstrap3.client.ui.base.ValueBoxBase;
028    import org.gwtbootstrap3.client.ui.constants.ValidationState;
029    
030    import com.google.gwt.editor.client.EditorError;
031    import com.google.gwt.event.logical.shared.AttachEvent;
032    import com.google.gwt.event.logical.shared.AttachEvent.Handler;
033    import com.google.gwt.user.client.ui.HasWidgets;
034    import 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>
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     */
053    public 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.setText("");
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                }
126                parent = parent.getParent();
127            }
128            if (inputWidget.isAttached() || validationStateParent != null) {
129                initialized = true;
130            }
131        }
132    
133        /** {@inheritDoc} */
134        @Override
135        public void showErrors(List<EditorError> errors) {
136            init();
137            // clearErrors();
138            String errorMsg = "";
139            if (validationStateParent != null) {
140                validationStateParent.setValidationState(errors.size() <= 0 ? ValidationState.NONE : ValidationState.ERROR);
141                for (int index = 0; index < errors.size(); index++) {
142                    errorMsg = errors.get(0).getMessage();
143                    if (index + 1 < errors.size()) errorMsg += "; ";
144                }
145            }
146            if (validationStateHelpBlock != null) {
147                validationStateHelpBlock.setText(errorMsg);
148            }
149        }
150    
151    }