001package gwt.material.design.client.base.validator;
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 com.google.gwt.event.shared.GwtEvent;
024import com.google.gwt.user.client.ui.Widget;
025import com.google.web.bindery.event.shared.EventBus;
026import com.google.web.bindery.event.shared.HandlerRegistration;
027import com.google.web.bindery.event.shared.SimpleEventBus;
028import gwt.material.design.client.base.validator.ValidationChangedEvent.ValidationChangedHandler;
029
030import java.util.LinkedHashMap;
031import java.util.Map;
032
033/**
034 * Useful for validating a group of fields that implement the {@link HasValidators} interface.
035 * 
036 * @author Steven Jardine
037 */
038public class GroupValidator implements ValidationChangedEvent.HasValidationChangedHandlers {
039
040    private final SimpleEventBus eventBus;
041
042    private boolean fireEvents = false;
043
044    private final Map<HasValidators<?>, Boolean> fields;
045
046    private final Map<HasValidators<?>, HandlerRegistration> registrations;
047
048    private Boolean groupValid = null;
049
050    /**
051     * Constructor.
052     */
053    public GroupValidator() {
054        fields = new LinkedHashMap<>();
055        registrations = new LinkedHashMap<>();
056        eventBus = new SimpleEventBus();
057    }
058
059    /**
060     * Adds a field to the group.
061     *
062     * @param <T> the generic type
063     * @param field the field
064     */
065    public <T extends Widget & HasValidators<?>> void add(final T field) {
066        fields.put(field, field.validate(false));
067        if (field.isAttached()) {
068            updateStateAndNotify();
069        }
070        registrations.put(field, field.addValidationChangedHandler(new ValidationChangedHandler() {
071            @Override
072            public void onValidationChanged(ValidationChangedEvent event) {
073                fields.put(field, event.isValid());
074                if (fireEvents) {
075                    updateStateAndNotify();
076                }
077            }
078        }));
079    }
080
081    @Override
082    public HandlerRegistration addValidationChangedHandler(ValidationChangedHandler handler) {
083        return eventBus.addHandler(ValidationChangedEvent.getType(), handler);
084    }
085
086    @Override
087    public void fireEvent(GwtEvent<?> event) {
088        eventBus.fireEvent(event);
089    }
090
091    /**
092     * Removes a field from the validation group.
093     *
094     * @param <T> the generic type
095     * @param field the field
096     * @return true, if successful
097     */
098    public <T extends Widget & HasValidators<?>> boolean remove(final T field) {
099        fields.remove(field);
100        HandlerRegistration reg = registrations.remove(field);
101        if (reg != null) {
102            reg.removeHandler();
103            return true;
104        }
105        return false;
106    }
107
108    /**
109     * Update the state of the validator and notify via {@link EventBus} any changed handlers.
110     */
111    protected void updateStateAndNotify() {
112        Boolean oldGroupValid = groupValid;
113        groupValid = true;
114        for (Boolean valid : fields.values()) {
115            groupValid &= valid;
116        }
117        if (groupValid != oldGroupValid) {
118            eventBus.fireEvent(new ValidationChangedEvent(groupValid));
119        }
120    }
121
122    /**
123     * Validate the group. This calls {@link Validator #validate(Editor, Object)} on each field in the group.
124     *
125     * @return true, if successful
126     */
127    public boolean validate() {
128        return validate(true);
129    }
130
131    /**
132     * Validate the group. This calls {@link Validator #validate(Editor, Object)} on each field in the group.
133     *
134     * @param show do we want to show the user the result of the validate via ui marks?
135     * @return true, if successful
136     */
137    public boolean validate(boolean show) {
138        fireEvents = false;
139        for (HasValidators<?> field : fields.keySet()) {
140            field.validate(show);
141        }
142        fireEvents = true;
143        updateStateAndNotify();
144        return groupValid;
145    }
146}