001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package com.sun.rave.web.ui.renderer;
042:
043: import java.io.IOException;
044:
045: import javax.faces.component.UIComponent;
046: import javax.faces.context.FacesContext;
047: import javax.faces.context.ResponseWriter;
048:
049: import com.sun.rave.web.ui.component.RadioButton;
050: import com.sun.rave.web.ui.component.RadioButtonGroup;
051: import com.sun.rave.web.ui.component.Selector;
052: import com.sun.rave.web.ui.model.Option;
053: import com.sun.rave.web.ui.theme.Theme;
054: import com.sun.rave.web.ui.theme.ThemeStyles;
055: import com.sun.rave.web.ui.util.ConversionUtilities;
056: import com.sun.rave.web.ui.util.ThemeUtilities;
057:
058: /**
059: * The <code>RadioButtonRenderer</code> renders a <code>RadioButtonGroup</code>
060: * component as set of radio buttons. The <code>RadioButtonGroupRenderer</code>
061: * creates an instance of <code>RadioButton</code> for each
062: * <code>Option</code> instance in the <code>Array</code>, <code>Map</code>, or
063: * <code>Collection</code> returned by the <code>RadioButtonGroup</code>
064: * <code>getItems()</code> method and renders them. It also
065: * creates a <code>Label</code> component and renders it as the label for the
066: * group.
067: * <p>
068: * Only one radio button may be selected at any time and one radio button
069: * must always be selected. The value of the <code>RadioButtonGroup</code>
070: * will determine which radio button shall be initially selected.
071: * Subsequently, the <code>RadioButtonGroup</code>'s value holds the
072: * currently selected radio button value.
073: * </p>
074: * <p>
075: * The radio buttons are rendered as a single column or some number of
076: * rows and columns. The rows and columns are rendered as a table as
077: * defined by the {@link com.sun.rave.web.ui.renderer.RowColumnRenderer} superclass.
078: * The elements
079: * that make up the radio button occupy a cell in the table.
080: * The style class selector for the group elements is identified by a java
081: * constants defined in the {@link com.sun.rave.web.ui.theme.ThemeStyles} class.
082: * </p>
083: * <ul>
084: * <li>RADIOBUTTON_GROUP for the TABLE element.</li>
085: * <li>RADIOBUTTON_GROUP_CAPTION for the TD element containing the group
086: * label</li>
087: * <li>RADIOBUTTON_GROUP_LABEL for the LABEL element used as the CAPTION</li>
088: * <li>RADIOBUTTON_GROUP_LABEL_DISABLED for the LABEL used as the CAPTION if
089: * the group is disabled</li>
090: * <li>RADIOBUTTON_GROUP_ROW_EVEN for even TR elements</li>
091: * <li>RADIOBUTTON_GROUP_ROW_ODD for odd TR elements</li>
092: * <li>RADIOBUTTON_GROUP_CELL_EVEN for even TD elements</li>
093: * <li>RADIOBUTTON_GROUP_CELL_ODD for odd TD elements</li>
094: * <li>RADIOBUTTON for the INPUT element</li>
095: * <li>RADIOBUTTON_DISABLED for the INPUT element for disabled radio
096: * button </li>
097: * <li>RADIOBUTTON_LABEL for a LABEL element of a radio button</li>
098: * <li>RADIOBUTTON_LABEL_DISABLED for a LABEL element of a disabled radio
099: * button</li>
100: * <li>RADIOBUTTON_IMAGE for an IMG element of a radio button</li>
101: * <li>RADIOBUTTON_IMAGE_DISABLED for an IMG element of a disabled radio
102: * button</li>
103: * </ul>
104: * <p>
105: * The <code>name</code> property of each radio button is the component id of
106: * the <code>RadioButtonGroup</code> instance. The id of a
107: * <code>RadioButton</code> component is <em>rbgrpid_N</em> where
108: * <em>rbgrpid</em> is the id of the
109: * <code>RadioButtonGroup</code> instance and <em>_N</em> is the nth
110: * radio button.
111: * </p>
112: * <p>
113: * The <code>RadioButtonGroup</code> is decoded by identifying the
114: * <code>RadioButtonGroup</code> instance component id which is
115: * returned as a request parameter. It represents the name attribute
116: * of the selected radio button's <input> element. The value of
117: * the identified request parameter is assigned as the submitted value of the
118: * <code>RadioButtonGroup</code> component.
119: * </p>
120: * <p>
121: * If the items property of the <code>RadioButtonGroup</code> is null or
122: * zero length no output is produced.
123: * </p>
124: *
125: */
126: public class RadioButtonGroupRenderer extends SelectorGroupRenderer {
127:
128: private final String MSG_COMPONENT_NOT_RADIOBUTTONGROUP = "RadioButtonGroupRender only renders RadioButtonGroup components."; //NOI18N
129:
130: /**
131: * Creates a new instance of RadioButtonGroupRenderer
132: */
133: public RadioButtonGroupRenderer() {
134: super ();
135: }
136:
137: /**
138: * Ensure that the component to be rendered is a RadioButtonGroup instance.
139: * Actual rendering occurs during <code>renderEnd</code>
140: *
141: * @param context FacesContext for the request we are processing.
142: * @param component UIComponent to be decoded.
143: */
144: public void renderStart(FacesContext context,
145: UIComponent component, ResponseWriter writer)
146: throws IOException {
147:
148: // Bail out if the component is not a RadioButtonGroup component.
149: if (!(component instanceof RadioButtonGroup)) {
150: throw new IllegalArgumentException(
151: MSG_COMPONENT_NOT_RADIOBUTTONGROUP);
152: }
153: }
154:
155: /**
156: * RadioButtonGroupRenderer renders the entire RadioButtonGroup
157: * component within the renderEnd method.
158: *
159: * @param context FacesContext for the request we are processing.
160: * @param component UIComponent to be decoded.
161: */
162: public void renderEnd(FacesContext context, UIComponent component,
163: ResponseWriter writer) throws IOException {
164:
165: // Use only the cols value. If not valid render a single column.
166: // If there are more items than columns, render additional rows.
167: //
168: RadioButtonGroup rbgrp = (RadioButtonGroup) component;
169:
170: Theme theme = ThemeUtilities.getTheme(context);
171: renderSelectorGroup(context, component, theme, writer, rbgrp
172: .getColumns());
173:
174: }
175:
176: /**
177: * Return a RadioButton component to render.
178: *
179: * @param context <code>FacesContext</code> for the current request
180: * @param component <code>CheckboxGroup</code> component rendered
181: * @param theme <code>Theme</code> for the component
182: * @param option the <code>Option</code> being rendered.
183: */
184: protected UIComponent getSelectorComponent(FacesContext context,
185: UIComponent component, Theme theme, String id, Option option) {
186:
187: RadioButtonGroup rbgrp = (RadioButtonGroup) component;
188:
189: RadioButton rb = new RadioButton();
190: rb.setId(id);
191: rb.setParent(component);
192: rb.setName(rbgrp.getClientId(context));
193: rb.setImageURL(option.getImage());
194: rb.setSelectedValue(option.getValue());
195: rb.setLabel(option.getLabel());
196: rb.setDisabled(rbgrp.isDisabled());
197: rb.setReadOnly(rbgrp.isReadOnly());
198: rb.setTabIndex(rbgrp.getTabIndex());
199:
200: //<RAVE>
201: // Bug Fix: 6274989
202: if (option.getTooltip() != null) {
203: rb.setToolTip(option.getTooltip());
204: } else {
205: rb.setToolTip(rbgrp.getToolTip());
206: }
207:
208: //mbohm 6300361,6300362
209: //transfer event attributes from rbgrp to rb
210: //see RowColumnRenderer.renderRowColumnLayout
211: transferEventAttributes(rbgrp, rb);
212: //</RAVE>
213:
214: // Default to not selected
215: //
216: rb.setSelected(null);
217:
218: // Need to check the submittedValue for immediate condition
219: //
220: String[] subValue = (String[]) rbgrp.getSubmittedValue();
221: if (subValue == null) {
222: if (isSelected(option, rbgrp.getSelected())) {
223: rb.setSelected(rb.getSelectedValue());
224: }
225: } else if (subValue.length != 0) {
226: Object selectedValue = rb.getSelectedValue();
227: String selectedValueAsString = ConversionUtilities
228: .convertValueToString(component, selectedValue);
229: if (subValue[0] != null
230: && subValue[0].equals(selectedValueAsString)) {
231: rb.setSelected(rb.getSelectedValue());
232: }
233: }
234:
235: return rb;
236: }
237:
238: /**
239: * Return true if the <code>item</item> argument is the currently
240: * selected radio button. Equality is determined by the <code>equals</code>
241: * method of the object instance stored as the <code>value</code> of
242: * <code>item</code>. Return false otherwise.
243: *
244: * @param item the current radio button being rendered.
245: * @param currentValue the value of the current selected radio button.
246: */
247: private boolean isSelected(Option item, Object currentValue) {
248: return currentValue != null && item.getValue() != null
249: && item.getValue().equals(currentValue);
250: }
251:
252: protected String[] styles = { ThemeStyles.RADIOBUTTON_GROUP, /* GRP */
253: ThemeStyles.RADIOBUTTON_GROUP_CAPTION, /* GRP_CAPTION */
254: ThemeStyles.RADIOBUTTON_GROUP_LABEL, /* GRP_LABEL */
255: ThemeStyles.RADIOBUTTON_GROUP_LABEL_DISABLED, /* GRP_CAPTION_DIS */
256: ThemeStyles.RADIOBUTTON_GROUP_ROW_EVEN, /* GRP_ROW_EVEN */
257: ThemeStyles.RADIOBUTTON_GROUP_ROW_ODD, /* GRP_ROW_EVEN */
258: ThemeStyles.RADIOBUTTON_GROUP_CELL_EVEN,/* GRP_CELL_EVEN */
259: ThemeStyles.RADIOBUTTON_GROUP_CELL_ODD, /* GRP_CELL_ODD */
260: ThemeStyles.RADIOBUTTON, /* INPUT */
261: ThemeStyles.RADIOBUTTON_DISABLED, /* INPUT_DIS */
262: ThemeStyles.RADIOBUTTON_LABEL, /* LABEL */
263: ThemeStyles.RADIOBUTTON_LABEL_DISABLED, /* LABEL_DIS */
264: ThemeStyles.RADIOBUTTON_IMAGE, /* IMAGE */
265: ThemeStyles.RADIOBUTTON_IMAGE_DISABLED, /* IMAGE_DIS */
266: ThemeStyles.LABEL_LEVEL_ONE_TEXT, /* LABEL_LVL1 */
267: ThemeStyles.LABEL_LEVEL_TWO_TEXT, /* LABEL_LVL2 */
268: ThemeStyles.LABEL_LEVEL_THREE_TEXT /* LABLE_LVL3 */
269: };
270:
271: /**
272: * Return style constants for a <code>RadioButton</code> component.
273: */
274: protected String[] getStyles() {
275: return styles;
276: }
277: }
|