All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.webui.jsf.renderkit.html.RadioButtonRenderer Maven / Gradle / Ivy

There is a newer version: 4.4.0.1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2007-2018 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://oss.oracle.com/licenses/CDDL+GPL-1.1
 * or LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.webui.jsf.renderkit.html;

import com.sun.faces.annotation.Renderer;
import java.io.IOException;
import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import com.sun.webui.jsf.component.RadioButton;
import com.sun.webui.theme.Theme;
import com.sun.webui.jsf.theme.ThemeStyles;
import com.sun.webui.jsf.util.ConversionUtilities;
import com.sun.webui.jsf.util.ThemeUtilities;

/**
 * 

* The RadioButtonRenderer renders a * {@link com.sun.webui.jsf.component.RadioButton} component. *

*

Encoding

*

* The RadioButtonRenderer renders a RadioButton as: *

    *
  • An INPUT element of type radio for each radio button. *
  • *
  • An optional image. The component rendered for this feature is obtained * from a call to getImageComponent() on the component being * rendered.
  • *
  • An optional label. The component rendered for this feature is obtained * from a call to getLabelComponent() on the component being * rendered.
  • * *
*

*

* The CSS selectors for the elements and components that comprise a * radio button are identified by java * constants defined in the {@link ThemeStyles} class. *

*
    *
  • RADIOBUTTON for the INPUT element
  • *
  • RADIOBUTTON_DISABLED for the INPUT element of a disabled radio * button
  • *
  • RADIOBUTTON_LABEL for label component if a label is rendered
  • *
  • RADIOBUTTON_LABEL_DISABLED for a label component of a disabled * radio button, if a label is rendered
  • *
  • RADIOBUTTON_IMAGE for an image component if an image is rendered
  • *
  • RADIOBUTTON_IMAGE_DISABLED for an image component of a disabled * radio button if an image is rendered.
  • *
* Note that these selectors are appended to any existing selectors * that may already exist on the styleClass property of the * RadioButton component and the optional image and label * components. *

* For more details on the encoding the * RadioButton component see the super class * {@link com.sun.webui.jsf.renderkit.html.RbCbRendererBase} *

*

*

Decoding

*

* If the INPUT element representing a radio button is selected on the * the client, the submitted request will contain a request parameter * whose name is the value of the name attribute of the selected * HTML INPUT element. The value of the request parameter will be the * value of the value attribute of the selected HTML INPUT element. *

*

* The component being decoded is selected if the component's * isDisabled and isReadOnly methods * return false and: *

*
    *
  • a request parameter exists that is equal to its name * property. If the name property is null, then a * request parameter exists that is equal to its clientId * property. *
  • *
*

* And *

*
    *
  • the request parameter's value is String.equal to the * the component's selectedValue property, after conversion * to a String, by calling * ConversionUtilities.convertValueToString. If the component * was encoded as a boolean control, then the request parameter's value * must be equal to the component's clientId property. *
  • *
*

* If selected, a String[1] array is assigned as the component's * submitted value where the single array element is the String * version of the selectedValue property or "true" if the * component was encoded as a boolean control.
* If not selected, a String[0] array is assigned as the * component's submitted value or a String[1] array where the * single array element is "false" if the component was encoded as a * boolean control. *

*

* If the component's isDisabled or isReadOnly * methods return true no submitted value is assigned to the component, * and results in a null submitted value implying the component * was not submitted, and the state of the component is unchanged. *

* Since the RadioButtonRenderer only renders a single * RadioButton component it cannot enforce that at least * one radio button should be selected among a group of RadioButton * components with the same name property. *

*

* If the RadioButton is selected, the selected * property will be the same value as the selectedValue * property. If more than one RadioButton component is * encoded with the same name property and more than one * RadioButton's is selectred, * the last selected RadioButton component that is encoded * will be appear as checked in the HTML page. Subsequently during the * next submit, only the checked RadioButton component * will be selected. *

*/ @Renderer(@Renderer.Renders(componentFamily = "com.sun.webui.jsf.RadioButton")) //FIXME check about making RbCbRendererBase a public abstract class public class RadioButtonRenderer extends RbCbRendererBase { private final String MSG_COMPONENT_NOT_RADIOBUTTON = "RadioButtonRenderer only renders RadioButton components."; /** * Creates a new instance of RadioButtonRenderer */ public RadioButtonRenderer() { super(); } /** *

Decode the RadioButton selection.

*

* If the value of the component's name property * has been set, the value is used to match a request parameter. * If it has not been set the component clientId is used to match * a request parameter. If a match is found, and the value of the * of the request parameter matches the String value of the * component's selectedValue property, the * radio button is selected. The component's submitted value is * assigned a String[1] array where the single array * element is the matching parameter value. *

*

* If no matching request parameter or value is found, an instance of * String[0] is assigned as the submitted value, * meaning that this is a component was not selected. *

*

* If the component was encoded as a boolean control the * value of the matching request attribute will be the component's * clientId property if selected. If selected the * submitted value is new String[] { "true" } * and new String[] { "false" } if not selected. *

*

* It is the developer's responsibility to ensure the validity of the * name property (the name attribute on the * INPUT element) by ensuring that it is unique to the radio buttons * for a given group within a form. *

* * @param context FacesContext for the request we are processing. * @param component The RadioButton * component to be decoded. */ @Override public void decode(FacesContext context, UIComponent component) { // We need to know the last state of the component before decoding // this radio button. This disabled check is not to determine // if the radio button was disabled on the client. // We assume that the disabled state is in the same state as it was // when this radio button was last rendered. // If the radio button was disabled then it can not have changed on // the client. We ignore the case that it might have been // enabled in javascript on the client. // This allows us to distinguish that no radio button was selected. // No radio buttons are selected when "isDisabled || isReadOnly -> false // and no request parameters match the name attribute if part of a // group or the clientId if a single radio button. // if (isDisabled(component) || isReadOnly(component)) { return; } // If there is a request parameter that that matches the // name property, this component is one of the possible // selections. We need to match the value of the parameter to the // the component's value to see if this is the selected component. // RadioButton radioButton = (RadioButton) component; String name = radioButton.getName(); boolean inGroup = name != null; // If name is null use the clientId. // if (name == null) { name = component.getClientId(context); } Map requestParameterMap = context.getExternalContext(). getRequestParameterMap(); // The request parameter map contains the INPUT element // name attribute value as a parameter. The value is the // the "selectedValue" value of the RadioButton component. // if (requestParameterMap.containsKey(name)) { String newValue = (String) requestParameterMap.get(name); // We need to discern the case where the radio button // is part of a group and it is a boolean radio button. // If the radio button is part of a group and it is a // boolean radio button then the submitted value contains the // value of "component.getClientId()". If // the value was not a unique value within the group // of boolean radio buttons, then all will appear selected, // since name will be the same for all the radio buttons // and the submitted value would always be "true" and then // every radio button component in the group would decode // as selected. Due to the HTML implementation of radio // buttons, only the last radio button will appear selected. // Object selectedValue = radioButton.getSelectedValue(); String selectedValueAsString = null; if (inGroup && selectedValue instanceof Boolean) { selectedValueAsString = component.getClientId(context); // Use the toString value of selectedValue even if // it is a Boolean control, in case the application // wants "FALSE == FALSE" to mean checked. // if (selectedValueAsString.equals(newValue)) { ((UIInput) component).setSubmittedValue( new String[]{selectedValue.toString()}); return; } } else { selectedValueAsString = ConversionUtilities.convertValueToString(component, selectedValue); if (selectedValueAsString.equals(newValue)) { ((UIInput) component).setSubmittedValue( new String[]{newValue}); return; } } // Not selected possibly deselected. // ((UIInput) component).setSubmittedValue(new String[0]); } return; } /** * Ensure that the component to be rendered is a RadioButton instance. * Actual rendering occurs during renderEnd * * @param context FacesContext for the request we are processing. * @param component UIComponent to be decoded. */ @Override public void renderStart(FacesContext context, UIComponent component, ResponseWriter writer) throws IOException { // Bail out if the component is not a RadioButton component. // This message should be logged. // if (!(component instanceof RadioButton)) { throw new IllegalArgumentException(MSG_COMPONENT_NOT_RADIOBUTTON); } } /** * RadioButtonRenderer renders the entire RadioButton * component within the renderEnd method. * * @param context FacesContext for the request we are processing. * @param component UIComponent to be decoded. */ @Override public void renderEnd(FacesContext context, UIComponent component, ResponseWriter writer) throws IOException { Theme theme = ThemeUtilities.getTheme(context); renderSelection(context, component, theme, writer, "radio"); } /** * Return true if the component is selected, false * otherwise. * * @param context FacesContext for the request we are processing. * @param component UIComponent to test for selected. */ protected boolean isSelected(FacesContext context, UIComponent component) { return ((RadioButton) component).isChecked(); } protected String[] styles = { ThemeStyles.RADIOBUTTON, /* INPUT */ ThemeStyles.RADIOBUTTON_DISABLED, /* INPUT_DIS */ ThemeStyles.RADIOBUTTON_LABEL, /* LABEL */ ThemeStyles.RADIOBUTTON_LABEL_DISABLED, /* LABEL_DIS */ ThemeStyles.RADIOBUTTON_IMAGE, /* IMAGE */ ThemeStyles.RADIOBUTTON_IMAGE_DISABLED, /* IMAGE_DIS */ ThemeStyles.RADIOBUTTON_SPAN, /* SPAN */ ThemeStyles.RADIOBUTTON_SPAN_DISABLED /* SPAN_DIS */}; /** * Return the style class name for the structural element indicated * by styleCode * * @param theme The Theme for this request. * @param styleCode identifies the style class for the element about * to be rendered. */ protected String getStyle(Theme theme, int styleCode) { String style = null; try { style = theme.getStyleClass(styles[styleCode]); } catch (Exception e) { // Don't care } return style; } }