/** * Copyright (C) 2009 BonitaSoft S.A. * BonitaSoft, 31 rue Gustave Eiffel - 38000 Grenoble * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2.0 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.bonitasoft.forms.client.view.widget; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.bonitasoft.forms.client.model.ReducedFormFieldAvailableValue; import org.bonitasoft.forms.client.view.common.DOMUtils; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.HasClickHandlers; import com.google.gwt.event.logical.shared.HasValueChangeHandlers; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.EventHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.RadioButton; import com.google.gwt.user.client.ui.Widget; /** * Widget displaying a group of radio buttons (only one radio button can be selected inside a group) * * @author Anthony Birembaut */ public class RadioButtonGroupWidget extends Composite implements HasClickHandlers, ClickHandler, HasValueChangeHandlers<Boolean>, ValueChangeHandler<Boolean> { protected static int radioButtonGroupIndex = 0; /** * Css class added to groupWidgets panel */ private static final String GROUP_WIDGETS = "group-widgets"; /** * the flow panel used to display the widget */ protected FlowPanel inputDiv; /** * flow panel used to contain all the widget checkboxes */ protected FlowPanel groupWidgets; /** * The set of radio buttons in the group */ protected Set<RadioButton> radioButtons = new HashSet<RadioButton>(); /** * items style */ protected String itemsStyle; /** * The radio buttons group Id */ protected String radioButtonGroupName; /** * click handlers registered for the widget */ protected List<ClickHandler> clickHandlers; /** * value change handlers registered for the widget */ protected List<ValueChangeHandler<Boolean>> valueChangeHandlers; /** * indicates if HTML is allowed as value of the widget */ protected boolean allowHTML; /** * indicates if the widget instance is a child of a multiple element */ protected boolean isElementOfMultipleWidget; /** * Constructor * * @param radioButtonGroupId * Id of the radio button group * @param availableValues * available values of the group * @param initialValue * initial value * @param itemsStyle * the css classes of each radio button * @param allowHTML * allow HTML in the radio buttons labels * */ public RadioButtonGroupWidget(final String radioButtonGroupId, final List<ReducedFormFieldAvailableValue> availableValues, final String initialValue, final String itemsStyle, final boolean allowHTML) { this(radioButtonGroupId, availableValues, initialValue, itemsStyle, allowHTML, false); } /** * Constructor * * @param radioButtonGroupId * Id of the radio button group * @param availableValues * available values of the group * @param initialValue * initial value * @param itemsStyle * the css classes of each radio button * @param allowHTML * allow HTML in the radio buttons labels * @param isElementOfMultipleWidget * indicates if the widget instance is a child of a multiple element * */ public RadioButtonGroupWidget(final String radioButtonGroupId, final List<ReducedFormFieldAvailableValue> availableValues, final String initialValue, final String itemsStyle, final boolean allowHTML, final boolean isElementOfMultipleWidget) { this.itemsStyle = itemsStyle; this.allowHTML = allowHTML; this.isElementOfMultipleWidget = isElementOfMultipleWidget; inputDiv = new FlowPanel(); groupWidgets = new FlowPanel(); groupWidgets.addStyleName(GROUP_WIDGETS); radioButtonGroupName = getRadioButtonGroupName(radioButtonGroupId); for (final ReducedFormFieldAvailableValue availableValue : availableValues) { final RadioButton radioButton = createRadioButton(radioButtonGroupName, availableValue, allowHTML); addItemsStyle(radioButton, itemsStyle); setInitialValue(radioButton, initialValue, availableValue); saveRadioButton(radioButton); groupWidgets.add(radioButton); } inputDiv.add(groupWidgets); initWidget(inputDiv); } private RadioButton createRadioButton(final String groupName, final ReducedFormFieldAvailableValue availableValue, final boolean allowHTML) { final RadioButton radioButton = new RadioButton(radioButtonGroupName, availableValue.getLabel(), allowHTML); radioButton.addClickHandler(this); radioButton.addValueChangeHandler(this); radioButton.setFormValue(availableValue.getValue()); radioButton.setStyleName("bonita_form_radio"); return radioButton; } private void addItemsStyle(final RadioButton radioButton, final String itemsStyle) { if (itemsStyle != null && itemsStyle.length() > 0) { radioButton.addStyleName(itemsStyle); } } private void setInitialValue(final RadioButton radioButton, final String initialValue, final ReducedFormFieldAvailableValue availableValue) { if (initialValue != null && initialValue.equals(availableValue.getValue())) { radioButton.setValue(true); } } /** * Useful in case the groups of radio buttons is displayed in several widget group instances * * @param radioButtonGroupId * the radio button definition Id * @return a name that can be used for the radio button group instance */ protected String getRadioButtonGroupName(final String radioButtonGroupId) { String radioButtonGroupName = null; if (isElementOfMultipleWidget) { if (radioButtonGroupIndex == 0) { radioButtonGroupName = radioButtonGroupId; } else { radioButtonGroupName = radioButtonGroupId + Integer.toString(radioButtonGroupIndex); } radioButtonGroupIndex++; } else { radioButtonGroupName = radioButtonGroupId; } return radioButtonGroupName; } /** * @return the String value of the slected radio button of the group (null if no radio button is selected) */ public String getValue() { String value = null; final Iterator<Widget> iterator = groupWidgets.iterator(); while (iterator.hasNext()) { final RadioButton radioButton = (RadioButton) iterator.next(); if (radioButton.getValue()) { value = radioButton.getFormValue(); break; } } return value; } /** * Set the value of the widget * * @param value * @param fireEvents */ public void setValue(final String value, final boolean fireEvents) { final String currentValue = getValue(); if (!(currentValue == null && value == null || currentValue != null && currentValue.equals(value))) { //don't do anything if the value of the widget doesn't change for (final RadioButton radioButton : radioButtons) { final DOMUtils domUtils = DOMUtils.getInstance(); final boolean newIsCheckedValue = value != null && value.equals(radioButton.getFormValue()); radioButton.setValue(newIsCheckedValue, fireEvents); domUtils.overrideNativeInputAfterUpdate(radioButton, newIsCheckedValue); } } } /** * Set the wigdet available values * * @param availableValues */ public void setAvailableValues(final List<ReducedFormFieldAvailableValue> availableValues, final boolean fireEvents) { clearRadioButtons(); for (final ReducedFormFieldAvailableValue availableValue : availableValues) { final RadioButton radioButton = createRadioButton(radioButtonGroupName, availableValue, allowHTML); addItemsStyle(radioButton, itemsStyle); saveRadioButton(radioButton); groupWidgets.add(radioButton); } if (fireEvents) { ValueChangeEvent.fire(this, true); } } private void saveRadioButton(final RadioButton radioButton) { radioButtons.add(radioButton); } private void clearRadioButtons() { radioButtons.clear(); groupWidgets.clear(); } /** * Enable or disable the radiobuttons group * * @param isEnabled */ public void setEnabled(final boolean isEnabled) { for (final RadioButton radioButton : radioButtons) { radioButton.setEnabled(isEnabled); } } /** * {@inheritDoc} */ @Override public HandlerRegistration addClickHandler(final ClickHandler clickHandler) { if (clickHandlers == null) { clickHandlers = new ArrayList<ClickHandler>(); } clickHandlers.add(clickHandler); return new EventHandlerRegistration(clickHandler); } /** * {@inheritDoc} */ @Override public HandlerRegistration addValueChangeHandler(final ValueChangeHandler<Boolean> valueChangeHandler) { if (valueChangeHandlers == null) { valueChangeHandlers = new ArrayList<ValueChangeHandler<Boolean>>(); } valueChangeHandlers.add(valueChangeHandler); return new EventHandlerRegistration(valueChangeHandler); } /** * {@inheritDoc} */ @Override public void onClick(final ClickEvent clickEvent) { if (clickHandlers != null) { for (final ClickHandler clickHandler : clickHandlers) { clickHandler.onClick(clickEvent); } } } /** * {@inheritDoc} */ @Override public void onValueChange(final ValueChangeEvent<Boolean> valueChangeEvent) { if (valueChangeHandlers != null) { for (final ValueChangeHandler<Boolean> valueChangeHandler : valueChangeHandlers) { valueChangeHandler.onValueChange(valueChangeEvent); } } } /** * Custom Handler registration */ protected class EventHandlerRegistration implements HandlerRegistration { protected EventHandler eventHandler; public EventHandlerRegistration(final EventHandler eventHandler) { this.eventHandler = eventHandler; } @Override public void removeHandler() { if (eventHandler instanceof ClickHandler) { clickHandlers.remove(eventHandler); } else if (eventHandler instanceof ValueChangeHandler<?>) { valueChangeHandlers.remove(eventHandler); } } } }