1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
5 *
6 * The contents of this file are subject to the terms of either the GNU
7 * General Public License Version 2 only ("GPL") or the Common Development
8 * and Distribution License("CDDL") (collectively, the "License"). You
9 * may not use this file except in compliance with the License. You can obtain
10 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
11 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
12 * language governing permissions and limitations under the License.
13 *
14 * When distributing the software, include this License Header Notice in each
15 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
16 * Sun designates this particular file as subject to the "Classpath" exception
17 * as provided by Sun in the GPL Version 2 section of the License file that
18 * accompanied this code. If applicable, add the following below the License
19 * Header, with the fields enclosed by brackets [] replaced by your own
20 * identifying information: "Portions Copyrighted [year]
21 * [name of copyright owner]"
22 *
23 * Contributor(s):
24 *
25 * If you wish your version of this file to be governed by only the CDDL or
26 * only the GPL Version 2, indicate your decision by adding "[Contributor]
27 * elects to include this software in this distribution under the [CDDL or GPL
28 * Version 2] license." If you don't indicate a single choice of license, a
29 * recipient has the option to distribute your version of this file under
30 * either the CDDL, the GPL Version 2 or to extend the choice of license to
31 * its licensees as provided above. However, if you add GPL Version 2 code
32 * and therefore, elected the GPL Version 2 license, then the option applies
33 * only if the new code is made subject to such option by the copyright
34 * holder.
35 */
36
37 /**
38 * $Id: SelectManyCheckboxListRenderer.java,v 1.57.4.5 2008/01/15 20:31:46 rlubke Exp $
39 *
40 * (C) Copyright International Business Machines Corp., 2001,2002
41 * The source code for this program is not published or otherwise
42 * divested of its trade secrets, irrespective of what has been
43 * deposited with the U. S. Copyright Office.
44 */
45
46 // SelectManyCheckboxListRenderer.java
47
48 package com.sun.faces.renderkit.html_basic;
49
50 import java.io.IOException;
51 import java.util.List;
52
53 import javax.faces.component.NamingContainer;
54 import javax.faces.component.UIComponent;
55 import javax.faces.component.ValueHolder;
56 import javax.faces.context.FacesContext;
57 import javax.faces.context.ResponseWriter;
58 import javax.faces.convert.Converter;
59 import javax.faces.model.SelectItem;
60 import javax.faces.model.SelectItemGroup;
61
62 import com.sun.faces.renderkit.AttributeManager;
63 import com.sun.faces.renderkit.RenderKitUtils;
64 import com.sun.faces.util.Util;
65 import com.sun.faces.util.RequestStateManager;
66
67 /**
68 * <B>SelectManyCheckboxListRenderer</B> is a class that renders the
69 * current value of <code>UISelectMany<code> component as a list of checkboxes.
70 */
71
72 public class SelectManyCheckboxListRenderer extends MenuRenderer {
73
74
75 private static final String[] ATTRIBUTES =
76 AttributeManager.getAttributes(AttributeManager.Key.SELECTMANYCHECKBOX);
77
78 // ---------------------------------------------------------- Public Methods
79
80
81 @Override
82 public void encodeEnd(FacesContext context, UIComponent component)
83 throws IOException {
84
85 rendererParamsNotNull(context, component);
86
87 if (!shouldEncode(component)) {
88 return;
89 }
90
91 ResponseWriter writer = context.getResponseWriter();
92 assert(writer != null);
93
94 String alignStr;
95 Object borderObj;
96 boolean alignVertical = false;
97 int border = 0;
98
99 if (null !=
100 (alignStr = (String) component.getAttributes().get("layout"))) {
101 alignVertical = alignStr.equalsIgnoreCase("pageDirection");
102 }
103 if (null != (borderObj = component.getAttributes().get("border"))) {
104 border = (Integer) borderObj;
105 }
106
107 Converter converter = null;
108 if(component instanceof ValueHolder) {
109 converter = ((ValueHolder)component).getConverter();
110 }
111
112 renderBeginText(component, border, alignVertical, context, true);
113
114 List<SelectItem> items = RenderKitUtils.getSelectItems(context, component);
115
116 if (!items.isEmpty()) {
117 Object currentSelections = getCurrentSelectedValues(component);
118 Object[] submittedValues = getSubmittedSelectedValues(component);
119 int idx = -1;
120 for (SelectItem curItem : items) {
121 idx++;
122 // If we come across a group of options, render them as a nested
123 // table.
124 if (curItem instanceof SelectItemGroup) {
125 // write out the label for the group.
126 if (curItem.getLabel() != null) {
127 if (alignVertical) {
128 writer.startElement("tr", component);
129 }
130 writer.startElement("td", component);
131 writer.writeText(curItem.getLabel(), component, "label");
132 writer.endElement("td");
133 if (alignVertical) {
134 writer.endElement("tr");
135 }
136
137 }
138 if (alignVertical) {
139 writer.startElement("tr", component);
140 }
141 writer.startElement("td", component);
142 writer.writeText("\n", component, null);
143 renderBeginText(component, 0, alignVertical,
144 context, false);
145 // render options of this group.
146 SelectItem[] itemsArray =
147 ((SelectItemGroup) curItem).getSelectItems();
148 for (int i = 0; i < itemsArray.length; ++i) {
149 renderOption(context,
150 component,
151 converter,
152 itemsArray[i],
153 currentSelections,
154 submittedValues,
155 alignVertical,
156 i);
157 }
158 renderEndText(component, alignVertical, context);
159 writer.endElement("td");
160 if (alignVertical) {
161 writer.endElement("tr");
162 writer.writeText("\n", component, null);
163 }
164 } else {
165 renderOption(context,
166 component,
167 converter,
168 curItem,
169 currentSelections,
170 submittedValues,
171 alignVertical,
172 idx);
173 }
174 }
175 }
176
177 renderEndText(component, alignVertical, context);
178
179 }
180
181 // ------------------------------------------------------- Protected Methods
182
183
184 protected void renderBeginText(UIComponent component, int border,
185 boolean alignVertical, FacesContext context,
186 boolean outerTable)
187 throws IOException {
188
189 ResponseWriter writer = context.getResponseWriter();
190 assert(writer != null);
191
192 writer.startElement("table", component);
193 if (border != Integer.MIN_VALUE) {
194 writer.writeAttribute("border", border, "border");
195 }
196
197 // render style and styleclass attribute on the outer table instead of
198 // rendering it as pass through attribute on every option in the list.
199 if (outerTable) {
200 // render "id" only for outerTable.
201 if (shouldWriteIdAttribute(component)) {
202 writeIdAttributeIfNecessary(context, writer, component);
203 }
204 String styleClass = (String) component.getAttributes().get(
205 "styleClass");
206 String style = (String) component.getAttributes().get("style");
207 if (styleClass != null) {
208 writer.writeAttribute("class", styleClass, "class");
209 }
210 if (style != null) {
211 writer.writeAttribute("style", style, "style");
212 }
213 }
214 writer.writeText("\n", component, null);
215
216 if (!alignVertical) {
217 writer.writeText("\t", component, null);
218 writer.startElement("tr", component);
219 writer.writeText("\n", component, null);
220 }
221
222 }
223
224
225 protected void renderEndText(UIComponent component,
226 boolean alignVertical,
227 FacesContext context)
228 throws IOException {
229
230 ResponseWriter writer = context.getResponseWriter();
231 assert(writer != null);
232
233 if (!alignVertical) {
234 writer.writeText("\t", component, null);
235 writer.endElement("tr");
236 writer.writeText("\n", component, null);
237 }
238 writer.endElement("table");
239
240 }
241
242
243 protected void renderOption(FacesContext context,
244 UIComponent component,
245 Converter converter,
246 SelectItem curItem,
247 Object currentSelections,
248 Object[] submittedValues,
249 boolean alignVertical,
250 int itemNumber) throws IOException {
251
252 ResponseWriter writer = context.getResponseWriter();
253 assert (writer != null);
254
255 // disable the check box if the attribute is set.
256 boolean componentDisabled = Util.componentIsDisabled(component);
257
258 String labelClass;
259 if (componentDisabled || curItem.isDisabled()) {
260 labelClass = (String) component.
261 getAttributes().get("disabledClass");
262 } else {
263 labelClass = (String) component.
264 getAttributes().get("enabledClass");
265 }
266 if (alignVertical) {
267 writer.writeText("\t", component, null);
268 writer.startElement("tr", component);
269 writer.writeText("\n", component, null);
270 }
271 writer.startElement("td", component);
272 writer.writeText("\n", component, null);
273
274 writer.startElement("input", component);
275 writer.writeAttribute("name", component.getClientId(context),
276 "clientId");
277 String idString =
278 component.getClientId(context) + NamingContainer.SEPARATOR_CHAR +
279 Integer.toString(itemNumber);
280 writer.writeAttribute("id", idString, "id");
281 String valueString = getFormattedValue(context, component,
282 curItem.getValue(), converter);
283 writer.writeAttribute("value", valueString, "value");
284 writer.writeAttribute("type", "checkbox", null);
285
286 Object valuesArray;
287 Object itemValue;
288 if (submittedValues != null) {
289 valuesArray = submittedValues;
290 itemValue = valueString;
291 } else {
292 valuesArray = currentSelections;
293 itemValue = curItem.getValue();
294 }
295
296 RequestStateManager.set(context,
297 RequestStateManager.TARGET_COMPONENT_ATTRIBUTE_NAME,
298 component);
299
300 if (isSelected(context, itemValue, valuesArray)) {
301 writer.writeAttribute(getSelectedTextString(), Boolean.TRUE, null);
302 }
303
304 // Don't render the disabled attribute twice if the 'parent'
305 // component is already marked disabled.
306 if (!Util.componentIsDisabled(component)) {
307 if (curItem.isDisabled()) {
308 writer.writeAttribute("disabled", true, "disabled");
309 }
310 }
311
312 // Apply HTML 4.x attributes specified on UISelectMany component to all
313 // items in the list except styleClass and style which are rendered as
314 // attributes of outer most table.
315 RenderKitUtils.renderPassThruAttributes(writer,
316 component,
317 ATTRIBUTES);
318 RenderKitUtils.renderXHTMLStyleBooleanAttributes(writer, component);
319
320 writer.endElement("input");
321 writer.startElement("label", component);
322 writer.writeAttribute("for", idString, "for");
323 // if enabledClass or disabledClass attributes are specified, apply
324 // it on the label.
325 if (labelClass != null) {
326 writer.writeAttribute("class", labelClass, "labelClass");
327 }
328 String itemLabel = curItem.getLabel();
329 if (itemLabel != null) {
330 writer.writeText(" ", component, null);
331 if (!curItem.isEscape()) {
332 // It seems the ResponseWriter API should
333 // have a writeText() with a boolean property
334 // to determine if it content written should
335 // be escaped or not.
336 writer.write(itemLabel);
337 } else {
338 writer.writeText(itemLabel, component, "label");
339 }
340 }
341 writer.endElement("label");
342 writer.endElement("td");
343 writer.writeText("\n", component, null);
344 if (alignVertical) {
345 writer.writeText("\t", component, null);
346 writer.endElement("tr");
347 writer.writeText("\n", component, null);
348 }
349 }
350
351 @Deprecated
352 protected void renderOption(FacesContext context,
353 UIComponent component,
354 Converter converter,
355 SelectItem curItem,
356 boolean alignVertical,
357 int itemNumber)
358 throws IOException {
359
360 renderOption(context,
361 component,
362 converter,
363 curItem,
364 getCurrentSelectedValues(component),
365 getSubmittedSelectedValues(component),
366 alignVertical,
367 itemNumber);
368
369 }
370
371 // ------------------------------------------------- Package Private Methods
372
373
374 String getSelectedTextString() {
375
376 return "checked";
377
378 }
379
380 } // end of class SelectManyCheckboxListRenderer