/**
* 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.Collection;
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.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Widget;
/**
* Widget displaying a group of checkboxes
*
* @author Anthony Birembaut
*/
public class CheckboxGroupWidget extends Composite implements HasClickHandlers, ClickHandler, HasValueChangeHandlers<Boolean>, ValueChangeHandler<Boolean> {
/**
* 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 checkboxes in the group
*/
protected Set<CheckBox> checkboxes = new HashSet<CheckBox>();
/**
* items style
*/
protected String itemsStyle;
protected List<ClickHandler> clickHandlers;
protected List<ValueChangeHandler<Boolean>> valueChangeHandlers;
protected boolean allowHTML;
/**
* Constructor
*
* @param availableValues
* available values of the group
* @param initialValues
* initial values
* @param itemsStyle
* the css classes of each radio button
*
*/
public CheckboxGroupWidget(final List<ReducedFormFieldAvailableValue> availableValues, final Collection<String> initialValues, final String itemsStyle) {
this(availableValues, initialValues, itemsStyle, false);
}
/**
* Constructor
*
* @param availableValues
* available values of the group
* @param initialValues
* initial values
* @param itemsStyle
* the css classes of each radio button
* @param allowHTML
* allow HTML in the checkboxes labels
*
*/
public CheckboxGroupWidget(final List<ReducedFormFieldAvailableValue> availableValues, final Collection<String> initialValues, final String itemsStyle,
final boolean allowHTML) {
inputDiv = new FlowPanel();
groupWidgets = new FlowPanel();
this.allowHTML = allowHTML;
this.itemsStyle = itemsStyle;
groupWidgets.addStyleName(GROUP_WIDGETS);
for (final ReducedFormFieldAvailableValue availableValue : availableValues) {
final CheckBox checkBox = createCheckbox(allowHTML, availableValue);
addItemsStyle(checkBox, itemsStyle);
setInitialValue(checkBox, initialValues, availableValue);
saveCheckbox(checkBox);
groupWidgets.add(checkBox);
}
inputDiv.add(groupWidgets);
initWidget(inputDiv);
}
private CheckBox createCheckbox(final boolean allowHTML, final ReducedFormFieldAvailableValue availableValue) {
final CheckBox checkBox = new CheckBox(availableValue.getLabel(), allowHTML);
checkBox.addClickHandler(this);
checkBox.addValueChangeHandler(this);
checkBox.setFormValue(availableValue.getValue());
checkBox.setStyleName("bonita_form_radio");
return checkBox;
}
private void addItemsStyle(final CheckBox checkBox, final String itemsStyle) {
if (itemsStyle != null && itemsStyle.length() > 0) {
checkBox.addStyleName(itemsStyle);
}
}
private void setInitialValue(final CheckBox checkBox,
final Collection<String> initialValues,
final ReducedFormFieldAvailableValue availableValue) {
if (initialValues != null && initialValues.contains(availableValue.getValue()))
{
checkBox.setValue(true);
}
}
/**
* @return the List of String value of the slected checkboxes of the group
*/
public List<String> getValue() {
final List<String> values = new ArrayList<String>();
final Iterator<Widget> iterator = groupWidgets.iterator();
while (iterator.hasNext()) {
final CheckBox checkBox = (CheckBox) iterator.next();
if (checkBox.getValue()) {
values.add(checkBox.getFormValue());
}
}
return values;
}
/**
* Set the value of the widget
*
* @param value
*/
public void setValue(final Collection<String> values, boolean fireEvents) {
final List<String> oldValues = getValue();
if (values != null && oldValues.containsAll(values) && values.containsAll(oldValues)) {
fireEvents = false;
}
for (final CheckBox checkbox : checkboxes) {
final DOMUtils domUtils = DOMUtils.getInstance();
if (values != null && values.contains(checkbox.getFormValue())) {
checkbox.setValue(true);
domUtils.overrideNativeInputAfterUpdate(checkbox, true);
} else {
checkbox.setValue(false);
domUtils.overrideNativeInputAfterUpdate(checkbox, false);
}
}
if (fireEvents) {
ValueChangeEvent.fire(this, true);
}
}
/**
* Set the wigdet available values
*
* @param availableValues
*/
public void setAvailableValues(final List<ReducedFormFieldAvailableValue> availableValues, final boolean fireEvents) {
clearCheckboxes();
for (final ReducedFormFieldAvailableValue availableValue : availableValues) {
final CheckBox checkBox = createCheckbox(allowHTML, availableValue);
addItemsStyle(checkBox, itemsStyle);
saveCheckbox(checkBox);
groupWidgets.add(checkBox);
}
if (fireEvents) {
ValueChangeEvent.fire(this, true);
}
inputDiv.add(groupWidgets);
}
private void clearCheckboxes() {
checkboxes.clear();
groupWidgets.clear();
}
private void saveCheckbox(final CheckBox checkBox) {
checkboxes.add(checkBox);
}
/**
* Enable or disable the checkbox group
*
* @param isEnabled
*/
public void setEnabled(final boolean isEnabled) {
for (final CheckBox checkBox : checkboxes) {
checkBox.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) {
for (final ClickHandler clickHandler : clickHandlers) {
clickHandler.onClick(clickEvent);
}
}
/**
* {@inheritDoc}
*/
@Override
public void onValueChange(final ValueChangeEvent<Boolean> valueChangeEvent) {
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);
}
}
}
}