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.component;
042:
043: import java.util.ArrayList;
044: import java.util.Map;
045:
046: import javax.faces.context.FacesContext;
047: import javax.faces.convert.ConverterException;
048: import javax.faces.render.Renderer;
049:
050: import com.sun.rave.web.ui.util.ConversionUtilities;
051:
052: /**
053: * <p>A component that represents a checkbox.</p>
054: * <p>
055: * The <code>Checkbox</code> can be used as a single checkbox
056: * or one checkbox among a group of checkboxes. A group
057: * of checkboxes represents a multiple selection list which can have any
058: * number of checkboxes selected, or none selected. A checkbox can
059: * represent a <code>Boolean</code> value, a <code>String</code> value,
060: * or a developer defined <code>Object</code> value.
061: * </p>
062: * <h3>Detecting a selected checkbox</h3>
063: * <p>
064: * The <code>Checkbox</code> uses both the <code>selected</code>
065: * and <code>selectedValue</code> properties to pass information about
066: * the checkbox's selection status. The <code>selected</code>
067: * property is used to indicate that the checkbox is selected.
068: * The <code>selectedValue</code> property is used to pass a data value,
069: * a string by default, for the checkbox. A checkbox is considered to be
070: * selected when the value of the <code>selected</code> property is equal
071: * to the value of the <code>selectedValue</code> property. A checkbox can
072: * be initally selected by assigning the same value
073: * to the <code>selectedValue</code> and the <code> selected</code>
074: * properties. <code>isChecked</code> is called to determine
075: * if this <code>Checkbox</code> is selected.
076: * </p>
077: * <p>If the <code>selectedValue</code> property is not specified or its
078: * value is <code>null</code> then the checkbox behaves like a
079: * boolean control. If the checkbox is selected, the value of the
080: * <code>selected</code> property is a true <code>Boolean</code>
081: * instance. If the checkbox is not selected, the value of the
082: * <code>selected</code> property will be a false <code>Boolean</code>
083: * instance.
084: * </p>
085: * <p> <em>Note that a value binding expression that evaluates to a
086: * primitive boolean value can be assigned to the <code>selected</code>
087: * property. Proper type coercion from <code>Boolean</code> to
088: * <code>boolean</code> occurs.</em>
089: * </p>
090: * <p>
091: * When checkboxes are part of a group, an <code>ArrayList</code> of
092: * selected checkboxes is maintained. If any checkboxes within a group are
093: * selected, a request attribute whose name is the value of the
094: * <code>name</code> property is created and added to the
095: * <code>RequestMap</code>. The request attribute value is an
096: * <code>ArrayList</code> containing the value of the
097: * <code>selectedValue</code> property of each selected
098: * checkbox. If no checkboxes are selected, no request attribute is
099: * created. The <code>selected</code> property of each selected checkbox
100: * within the group will also contain the value of the
101: * <code>selectedValue</code> property of the respective selected checkbox.
102: * </p>
103: * <h3>Using a <code>checkbox</code> tag as a boolean control</h3>
104: * <p>
105: * If the <code>selectedValue</code> property is not specified or its
106: * value is <code>null</code> then the checkbox behaves like a
107: * boolean control.
108: * </p>
109: * <p>
110: * To use the <code>Checkbox</code> as a boolean control, do not
111: * specify a value for the <code>selectedValue</code> property. The
112: * checkbox is selected if the <code>selected</code> property is not
113: * null and has the value of a Boolean instance with a <code>true</code>
114: * value. If the checkbox is not selected, then the value of the
115: * <code>selected</code> property is a false <code>Boolean</code> instance.
116: * </p>
117: * <p><em>Note that using a boolean checkbox in a group and
118: * referencing the request property for the selected checkboxes is not
119: * useful, since the value of the request property will be an <code>ArrayList
120: * </code> of indistinguishable <code>true</code> values.</em>
121: * </p>
122: * <h3>Using a <code>Checkbox</code> to represent a developer defined
123: * value</h3>
124: * <p> The <code>selectedValue</code> property can be assigned a
125: * developer defined object value to represent the value of a selected
126: * checkbox. If the checkbox is selected, the value of the <code>selected</code>
127: * property is assigned the value of the <code>selectedValue</code>
128: * property.
129: * </p>
130: * <p>
131: * If the value of the <code>selectedValue</code> property is a
132: * developer defined object, a <code>Converter</code> must be registered
133: * to convert to and from a <code>String</code> value.<br>
134: * In addition the object must support an
135: * <code>equals</code> method that returns <code>true</code> when the
136: * value of the <code>selectedValue</code> property is compared to
137: * the <code>selected</code> property value in order to detect a
138: * selected checkbox.
139: * </p>
140: * <h3>Using a <code>Checkbox</code> as one control in a group</h3>
141: * <p>
142: * The <code>name</code> property determines whether a
143: * checkbox is part of a group. A checkbox is treated as part of a group
144: * of checkboxes if the <code>name</code> property of the checkbox is
145: * assigned a value equal to the <code>name</code> property of the other
146: * checkboxes in the group. In other words, all checkboxes of a group have the
147: * same <code>name</code> property value. The group behaves
148: * like a multiple selection list, where zero or more checkboxes
149: * can be selected. The value of the name property must
150: * be unique within the scope of the Form parent containing the
151: * checkboxes.
152: * </p>
153: * <h3>Facets</h3>
154: * <p>
155: * The following facets are supported:
156: * </p>
157: * <ul>
158: * <li><em>image</em> If the image facet exists, it replaces the
159: * {@link com.sun.rave.web.ui.component.ImageComponent} subcompoent
160: * normally created for the image associated with the checkbox
161: * if the <code>imageURL</code> property is not null.</li>
162: * <li><em>label</em> If the label facet exists, it replaces the
163: * {@link com.sun.rave.web.ui.component.Label} subcomponent normally
164: * created for the label associated with the checkbox, if the
165: * label property is not null.</li>
166: * </ul>
167: * <p>
168: * Add an image or label facet to the <code>Checkbox</code> if more
169: * control over the properties of the subcomponents is needed.
170: * </p>
171: * <p>
172: * <em>Note that if a facet is exists, <code>Checkbox</code> properties
173: * that would normally be assigned to the created subcomponent, will
174: * not be assigned to the facet</em>
175: * </p>
176: * <p>
177: * <em>Note that unexpected layout of the <code>Checkbox</code> may occur
178: * if the component specified by the facet is not a
179: * {@link com.sun.rave.web.ui.component.ImageComponent} for the image facet or
180: * {@link com.sun.rave.web.ui.component.Label} for the label facet.</em>
181: * </p>
182: * <h3>ImageComponent and Label subcomponents</h3>
183: * <p>
184: * An image and a label may be associated with the <code>Checkbox</code>.<br/>
185: * If the <code>imageURL</code> property is not null and an image facet
186: * does not exist then a {@link com.sun.rave.web.ui.component.ImageComponent}
187: * component is created.<br/>
188: * If the <code>label</code> property is not null and a label facet does not
189: * exist then a {@link com.sun.rave.web.ui.component.Label} component is
190: * created.
191: * </p>
192: * <p>
193: * The following <code>Checkbox</code> properties are assigned to the
194: * subcomponents only if a facet does not exist.<br/>
195: * For the {@link com.sun.rave.web.ui.component.ImageComponent} subcomponent
196: * <ul>
197: * <li>this.getId() + "_image" is assigned to the <code>id</code> property.</li>
198: * <li>this.getImageURL() is assigned to the <code>url</code> property.</li>
199: * <li>this.getToolTip() is assigned to the <code>toolTip</code> property.</li>
200: * <li>this.getToolTip() is assigned to the <code>alt</code> property.</li>
201: * <li>this.isVisible() is assigned to the <code>visible</code> property.</li>
202: * <li>this.isRendered() is assigned to the <code>renderer</code> property.</li>
203: * </ul>
204: * </p>
205: * <p>
206: * For the {@link com.sun.rave.web.ui.component.Label} subcomponent
207: * <ul>
208: * <li>this.getId() + "_label" is assigned to the <code>id</code>
209: * property.</li>
210: * <li>this.getClientId() is assigned to the <code>for</code>
211: * property.</li>
212: * <li>this.getLabel() is assigned to the <code>text</code> property.</li>
213: * <li>this.getLabelLevel is assigned to the <code>labelLevel</code> property.</li>
214: * <li>this.getToolTip is assigned to the <code>toolTip</code> property.</li>
215: * <li>this.isVisible is assigned to the <code>visible</code> property.</li>
216: * <li>this.isRendered is assigned to the <code>renderer</code> property.</li>
217: * </ul>
218: * </ul>
219: * </p>
220: * <em>Note that if a value binding exists for one of the <code>Checkbox</code>
221: * properties mentioned above, the value binding is set on the subcomponent
222: * for that property.</em>
223: * </p>
224: */
225: public class Checkbox extends CheckboxBase {
226:
227: /**
228: * Constructor for a <code>Checkbox</code>.
229: */
230: public Checkbox() {
231: super ();
232: // When used in a group you can choose multiple
233: // and this behavior is provided, but the single
234: // implementation of Checkbox vs. CheckboxGroup
235: // does not need Multiple to be explicit.
236: //
237: setMultiple(false);
238: }
239:
240: /**
241: * Return an <code>ArrayList</code> containing the value of the
242: * <code>selectedValue</code> property of each selected checkbox
243: * in the group of checkboxes identified by the <code>name</code>
244: * parameter.
245: * A <code>Checkbox</code> is one of a group of checkboxes
246: * if more than on checkbox has the same value for the
247: * <code>name</code> property.<br/>
248: * When one of the checkboxes among that group is selected,
249: * the value of its <code>selectedValue</code> property
250: * is maintained within an <code>ArrayList</code> that is stored
251: * in a request attribute identified by the value of its <code>name</code>
252: * property.
253: *
254: * @param name the value a Checkbox name property.
255: */
256: public static ArrayList getSelected(String name) {
257:
258: Map rm = FacesContext.getCurrentInstance().getExternalContext()
259: .getRequestMap();
260:
261: if (name != null) {
262: return (ArrayList) rm.get(name);
263: } else {
264: return null;
265: }
266: }
267:
268: /**
269: * <p>Update the request parameter that holds the value of the
270: * <code>selectedValue</code> property of the selected check box.</p>
271: * If the <code>name</code> property has been set
272: * a request attribute is created.
273: * The value of the <code>name</code> property will
274: * be used for the request attribute name and the value of the request
275: * attribute will be an <code>ArrayList</code> containing the value of the
276: * <code>selectedValue</code> property of the selected check boxes
277: * that have the same <code>name</code> property value.
278: * If no check box is selected then no request attribute
279: * will be created.
280: * </p>
281: * <p>
282: * The request attribute described above is available during
283: * a <code>ValueChangeEvent</code>.
284: * </p>
285: *
286: * @param context The context of this request.
287: */
288: public void validate(FacesContext context) {
289:
290: super .validate(context);
291:
292: // If not valid or in a group don't add the checkbox to
293: // the request map.
294: //
295: if (!isValid()) {
296: return;
297: }
298: String groupName = getName();
299: if (groupName == null) {
300: return;
301: }
302:
303: // If the submitted value is valid and the
304: // checkbox is selected add it to the
305: // request map array list. To check if the component
306: // is selected, can't call "isChecked" or getValue()
307: // cause if there is a value binding, it will return the previously
308: // selected state and not the state of this submit
309: // so use getLocalValue() which is set if isValid is true.
310: //
311: Object selected = getLocalValue();
312: if (!getSelectedValue().equals(selected)) {
313: return;
314: }
315:
316: addToRequestMap(context, groupName, selected);
317: }
318:
319: protected void addToRequestMap(FacesContext context,
320: String groupName, Object selected) {
321:
322: Map requestMap = context.getExternalContext().getRequestMap();
323: ArrayList selectedCB = (ArrayList) requestMap.get(groupName);
324: if (selectedCB == null) {
325: selectedCB = new ArrayList();
326: requestMap.put(groupName, selectedCB);
327: }
328: if (!selectedCB.contains(selected)) {
329: selectedCB.add(selected);
330: }
331: }
332: }
|