/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.forms.formmodel; import java.util.Locale; import org.apache.cocoon.forms.FormContext; import org.apache.cocoon.forms.FormsConstants; import org.apache.cocoon.forms.event.ValueChangedEvent; import org.apache.cocoon.forms.event.ValueChangedListener; import org.apache.cocoon.forms.event.ValueChangedListenerEnabled; import org.apache.cocoon.forms.event.WidgetEvent; import org.apache.cocoon.forms.event.WidgetEventMulticaster; import org.apache.cocoon.forms.validation.ValidationError; import org.apache.cocoon.forms.validation.ValidationErrorAware; import org.apache.cocoon.xml.AttributesImpl; import org.apache.cocoon.xml.XMLUtils; import org.apache.commons.lang.BooleanUtils; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; /** * A widget to select a boolean value. Usually rendered as a checkbox. * * <p>You may wonder why we don't use a {@link Field} widget with an associated * Boolean Datatype instead. The reason is that many of the features of the Field * widget are overkill for a Boolean: validation is unnecessary (if the field is * not true it is false), the selectionlist associated with a Datatype also * has no purpose here (there would always be only 2 choices: true or false), * and the manner in which the request parameter of this widget is interpreted * is different (missing or empty request parameter means 'false', rather than null value). * * @version $Id$ */ public class BooleanField extends AbstractWidget implements ValidationErrorAware, ValueChangedListenerEnabled { private static final String BOOLEAN_FIELD_EL = "booleanfield"; private static final String VALUE_EL = "value"; private static final String VALIDATION_MSG_EL = "validation-message"; // FIXME(SW) : should the initial value be false or null ? This would allow // event listeners to be triggered at bind time. private Boolean value = Boolean.FALSE; private final BooleanFieldDefinition definition; /** Additional listeners to those defined as part of the widget definition (if any). */ private ValueChangedListener listener; protected ValidationError validationError; public BooleanField(BooleanFieldDefinition definition) { super(definition); this.definition = definition; this.listener = definition.getValueChangedListener(); } public WidgetDefinition getDefinition() { return this.definition; } public void initialize() { Boolean value = this.definition.getInitialValue(); if (value != null) { setValue(value); } super.initialize(); } public void readFromRequest(FormContext formContext) { if (!getCombinedState().isAcceptingInputs()) { return; } validationError = null; Object oldValue = value; String param = formContext.getRequest().getParameter(getRequestParameterName()); value = BooleanUtils.toBooleanObject(definition.getTrueParamValue().equals(param)); if (!value.equals(oldValue)) { getForm().addWidgetEvent(new ValueChangedEvent(this, oldValue, value)); } } /** * Returns the validation error, if any. There will always be a validation error in case the * {@link #validate()} method returned false. */ public ValidationError getValidationError() { return validationError; } /** * Set a validation error on this field. This allows fields to be externally marked as invalid by * application logic. * * @param error the validation error */ public void setValidationError(ValidationError error) { this.validationError = error; getForm().addWidgetUpdate(this); } /** * @return "booleanfield" */ public String getXMLElementName() { return BOOLEAN_FIELD_EL; } protected AttributesImpl getXMLElementAttributes() { AttributesImpl attrs = super.getXMLElementAttributes(); // Add the parameter value for true attrs.addCDATAAttribute("true-value", definition.getTrueParamValue()); return attrs; } public void generateItemSaxFragment(ContentHandler contentHandler, Locale locale) throws SAXException { // value element contentHandler.startElement(FormsConstants.INSTANCE_NS, VALUE_EL, FormsConstants.INSTANCE_PREFIX_COLON + VALUE_EL, XMLUtils.EMPTY_ATTRIBUTES); String stringValue = BooleanUtils.toBoolean(value) ? definition.getTrueParamValue() : "false"; contentHandler.characters(stringValue.toCharArray(), 0, stringValue.length()); contentHandler.endElement(FormsConstants.INSTANCE_NS, VALUE_EL, FormsConstants.INSTANCE_PREFIX_COLON + VALUE_EL); // validation message element: only present if the value is not valid if (validationError != null) { contentHandler.startElement(FormsConstants.INSTANCE_NS, VALIDATION_MSG_EL, FormsConstants.INSTANCE_PREFIX_COLON + VALIDATION_MSG_EL, XMLUtils.EMPTY_ATTRIBUTES); validationError.generateSaxFragment(contentHandler); contentHandler.endElement(FormsConstants.INSTANCE_NS, VALIDATION_MSG_EL, FormsConstants.INSTANCE_PREFIX_COLON + VALIDATION_MSG_EL); } } public Object getValue() { return value; } /** * Sets value of the field. If value is null, it is considered to be false * (see class comment). */ public void setValue(Object object) { if (object == null) { object = Boolean.FALSE; } if (!(object instanceof Boolean)) { throw new RuntimeException("Cannot set value of boolean field '" + getRequestParameterName() + "' to a non-Boolean value."); } Object oldValue = value; value = (Boolean)object; if (!value.equals(oldValue)) { Form form = getForm(); if (hasValueChangedListeners() || this.getForm().hasFormHandler()) { form.addWidgetEvent(new ValueChangedEvent(this, oldValue, value)); } form.addWidgetUpdate(this); } } /** * Adds a ValueChangedListener to this widget instance. Listeners defined * on the widget instance will be executed in addtion to any listeners * that might have been defined in the widget definition. */ public void addValueChangedListener(ValueChangedListener listener) { this.listener = WidgetEventMulticaster.add(this.listener, listener); } public void removeValueChangedListener(ValueChangedListener listener) { this.listener = WidgetEventMulticaster.remove(this.listener, listener); } public boolean hasValueChangedListeners() { return this.listener != null; } public void broadcastEvent(WidgetEvent event) { if (event instanceof ValueChangedEvent) { if (this.listener != null) { this.listener.valueChanged((ValueChangedEvent)event); } } else { // Other kinds of events super.broadcastEvent(event); } } }