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