1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.renderkit.html.ext;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.apache.myfaces.component.UserRoleUtils;
24 import org.apache.myfaces.shared_tomahawk.component.DisplayValueOnlyCapable;
25 import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
26 import org.apache.myfaces.component.html.ext.HtmlSelectManyCheckbox;
27 import org.apache.myfaces.custom.checkbox.HtmlCheckbox;
28 import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
29 import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
30 import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlCheckboxRendererBase;
31 import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
32
33 import javax.faces.FacesException;
34 import javax.faces.component.UIComponent;
35 import javax.faces.component.UISelectMany;
36 import javax.faces.component.UISelectBoolean;
37 import javax.faces.context.FacesContext;
38 import javax.faces.context.ResponseWriter;
39 import javax.faces.convert.Converter;
40 import javax.faces.model.SelectItem;
41 import javax.faces.model.SelectItemGroup;
42
43 import java.io.IOException;
44 import java.util.List;
45 import java.util.Set;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 public class HtmlCheckboxRenderer
68 extends HtmlCheckboxRendererBase
69 {
70 private static final Log log = LogFactory.getLog(HtmlCheckboxRenderer.class);
71
72 private static final String PAGE_DIRECTION = "pageDirection";
73
74 private static final String LINE_DIRECTION = "lineDirection";
75
76 private static final String LAYOUT_SPREAD = "spread";
77
78 public void encodeEnd(FacesContext context, UIComponent component) throws IOException
79 {
80 if (context == null) throw new NullPointerException("context");
81 if (component == null) throw new NullPointerException("component");
82
83 if (component instanceof HtmlCheckbox)
84 {
85 renderSingleCheckbox(context, (HtmlCheckbox)component);
86 }
87 else if (component instanceof DisplayValueOnlyCapable && HtmlRendererUtils.isDisplayValueOnly(component))
88 {
89 HtmlRendererUtils.renderDisplayValueOnlyForSelects(context, component);
90 }
91 else if (component instanceof UISelectMany)
92 {
93 String layout = getLayout((UISelectMany)component);
94 if (layout != null && layout.equals(LAYOUT_SPREAD))
95 {
96 return;
97 }
98 else
99 {
100 super.encodeEnd(context, component);
101 }
102 }
103 else if(component instanceof UISelectBoolean)
104 {
105 super.encodeEnd(context,component);
106 }
107 else
108 {
109 throw new IllegalArgumentException("Unsupported component class " + component.getClass().getName());
110 }
111 }
112
113 public void renderCheckboxList(FacesContext facesContext,
114 UISelectMany selectMany) throws IOException
115 {
116 final String layout = getLayout(selectMany);
117 if (layout != null)
118 {
119 Converter converter = getConverter(facesContext, selectMany);
120 if (layout.equals(PAGE_DIRECTION))
121 {
122 renderCheckboxListVertically(facesContext, selectMany,
123 converter);
124 }
125 else if (layout.equals(LINE_DIRECTION))
126 {
127 renderCheckboxListHorizontally(facesContext, selectMany,
128 converter);
129 }
130 else
131 {
132 log.error("Wrong layout attribute for component "
133 + selectMany.getClientId(facesContext) + ": " + layout);
134 }
135 }
136 }
137
138 protected void renderCheckboxListHorizontally(FacesContext facesContext,
139 UISelectMany selectMany, Converter converter) throws IOException
140 {
141 Set lookupSet = RendererUtils.getSubmittedValuesAsSet(facesContext,
142 selectMany, converter, selectMany);
143 boolean useSubmittedValues = lookupSet != null;
144 if (!useSubmittedValues)
145 {
146 lookupSet = RendererUtils.getSelectedValuesAsSet(facesContext,
147 selectMany, converter, selectMany);
148 }
149
150 ResponseWriter writer = facesContext.getResponseWriter();
151 writer.startElement(HTML.TABLE_ELEM, selectMany);
152 HtmlRendererUtils.renderHTMLAttributes(writer, selectMany,
153 HTML.SELECT_TABLE_PASSTHROUGH_ATTRIBUTES);
154 HtmlRendererUtils.writeIdIfNecessary(writer, selectMany, facesContext);
155
156 final int numRows = getLayoutWidth(selectMany);
157 for (int i = 0; i < numRows; i++)
158 {
159 renderRowForHorizontal(facesContext, selectMany, converter,
160 lookupSet, writer, numRows, i);
161 }
162
163 writer.endElement(HTML.TABLE_ELEM);
164 }
165
166 protected void renderRowForHorizontal(FacesContext facesContext,
167 UISelectMany selectMany, Converter converter, Set lookupSet,
168 ResponseWriter writer, int totalRows, int rowNum)
169 throws IOException
170 {
171
172 writer.startElement(HTML.TR_ELEM, selectMany);
173 int colNum = 0;
174 List items = RendererUtils.getSelectItemList(selectMany);
175 for (int count = rowNum; count < items.size(); count++)
176 {
177 int mod = count % totalRows;
178 if (mod == rowNum)
179 {
180 colNum++;
181 SelectItem selectItem = (SelectItem) items.get(count);
182 writer.startElement(HTML.TD_ELEM, selectMany);
183 renderGroupOrItemCheckbox(facesContext, selectMany, selectItem,
184 lookupSet != null, lookupSet, converter, false);
185 writer.endElement(HTML.TD_ELEM);
186 }
187 }
188 int totalItems = items.size();
189 int totalCols = (totalItems / totalRows);
190 if (totalItems % totalRows != 0)
191 {
192 totalCols++;
193 }
194 if (colNum < totalCols)
195 {
196 writer.startElement(HTML.TD_ELEM, selectMany);
197 writer.endElement(HTML.TD_ELEM);
198 }
199 writer.endElement(HTML.TR_ELEM);
200 }
201
202 protected void renderCheckboxListVertically(FacesContext facesContext,
203 UISelectMany selectMany, Converter converter) throws IOException
204 {
205
206 Set lookupSet = RendererUtils.getSubmittedValuesAsSet(facesContext,
207 selectMany, converter, selectMany);
208 boolean useSubmittedValues = lookupSet != null;
209 if (!useSubmittedValues)
210 {
211 lookupSet = RendererUtils.getSelectedValuesAsSet(facesContext,
212 selectMany, converter, selectMany);
213 }
214
215 ResponseWriter writer = facesContext.getResponseWriter();
216 writer.startElement(HTML.TABLE_ELEM, selectMany);
217 HtmlRendererUtils.renderHTMLAttributes(writer, selectMany,
218 HTML.SELECT_TABLE_PASSTHROUGH_ATTRIBUTES);
219 HtmlRendererUtils.writeIdIfNecessary(writer, selectMany, facesContext);
220
221 List items = RendererUtils.getSelectItemList(selectMany);
222 int totalItems = items.size();
223 for (int count = 0; count < totalItems; count++)
224 {
225 writer.startElement(HTML.TR_ELEM, selectMany);
226 final int numCols = getLayoutWidth(selectMany);
227 for (int i = 0; i < numCols; i++)
228 {
229 writer.startElement(HTML.TD_ELEM, selectMany);
230 if (count < totalItems)
231 {
232 SelectItem selectItem = (SelectItem) items.get(count);
233 renderGroupOrItemCheckbox(facesContext, selectMany,
234 selectItem, lookupSet != null, lookupSet,
235 converter, true);
236 }
237 writer.endElement(HTML.TD_ELEM);
238 if (i < numCols - 1)
239 {
240 count += 1;
241 }
242 }
243 writer.endElement(HTML.TR_ELEM);
244 }
245 writer.endElement(HTML.TABLE_ELEM);
246 }
247
248 protected void renderGroupOrItemCheckbox(FacesContext facesContext,
249 UIComponent uiComponent, SelectItem selectItem,
250 boolean useSubmittedValues, Set lookupSet,
251 Converter converter, boolean pageDirectionLayout) throws IOException {
252 ResponseWriter writer = facesContext.getResponseWriter();
253
254 boolean isSelectItemGroup = (selectItem instanceof SelectItemGroup);
255
256 if (isSelectItemGroup)
257 {
258 SelectItemGroup selectItemGroup = (SelectItemGroup) selectItem;
259 renderCheckboxGroup(facesContext, uiComponent, selectItemGroup,
260 useSubmittedValues, lookupSet, converter,
261 pageDirectionLayout);
262 }
263 else
264 {
265 UISelectMany selectMany = (UISelectMany) uiComponent;
266 Object itemValue = selectItem.getValue();
267 String itemStrValue = getItemStringValue(facesContext, selectMany,
268 converter, itemValue);
269
270 boolean checked = (useSubmittedValues && lookupSet
271 .contains(itemStrValue))
272 || (!useSubmittedValues && lookupSet.contains(itemValue));
273
274 boolean disabled = selectItem.isDisabled();
275
276 writer.startElement(HTML.LABEL_ELEM, selectMany);
277 renderLabelClassIfNecessary(facesContext, selectMany, disabled);
278 renderCheckbox(facesContext, selectMany, itemStrValue, disabled, checked, false,0);
279 writer.write(HTML.NBSP_ENTITY);
280 if(selectItem.isEscape())
281 {
282 writer.writeText(selectItem.getLabel(), null);
283 }
284 else
285 {
286 writer.write(selectItem.getLabel());
287 }
288 writer.endElement(HTML.LABEL_ELEM);
289 }
290 }
291
292 protected void renderLabelClassIfNecessary(FacesContext facesContext,
293 UISelectMany selectMany, boolean disabled) throws IOException
294 {
295 String labelClass = null;
296 boolean componentDisabled = isDisabled(facesContext, selectMany);
297 if (componentDisabled || disabled)
298 {
299 labelClass = (String) selectMany.getAttributes().get(
300 JSFAttr.DISABLED_CLASS_ATTR);
301 }
302 else
303 {
304 labelClass = (String) selectMany.getAttributes().get(
305 JSFAttr.ENABLED_CLASS_ATTR);
306 }
307 if (labelClass != null)
308 {
309 ResponseWriter writer = facesContext.getResponseWriter();
310 writer.writeAttribute("class", labelClass, "labelClass");
311 }
312 }
313
314 protected void renderCheckboxGroup(FacesContext facesContext,
315 UIComponent uiComponent, SelectItemGroup selectItemGroup,
316 boolean useSubmittedValues, Set lookupSet,
317 Converter converter, boolean pageDirectionLayout) throws IOException {
318 ResponseWriter writer = facesContext.getResponseWriter();
319 UISelectMany selectMany = (UISelectMany)uiComponent;
320 writer.startElement(HTML.TABLE_ELEM, selectMany);
321 if (pageDirectionLayout)
322 writer.startElement(HTML.TR_ELEM, selectMany);
323 writer.startElement(HTML.TD_ELEM, selectMany);
324 writer.write(selectItemGroup.getLabel());
325 writer.endElement(HTML.TD_ELEM);
326
327 if (pageDirectionLayout) {
328 writer.endElement(HTML.TR_ELEM);
329 writer.startElement(HTML.TR_ELEM, selectMany);
330 }
331 writer.startElement(HTML.TD_ELEM, selectMany);
332 writer.startElement(HTML.TABLE_ELEM, selectMany);
333 writer.writeAttribute(HTML.BORDER_ATTR, "0", null);
334
335 SelectItem[] selectItems = selectItemGroup.getSelectItems();
336 for (int i=0; i<selectItems.length; i++) {
337 renderGroupOrItemCheckbox(facesContext, selectMany, selectItems[i], useSubmittedValues, lookupSet, converter, pageDirectionLayout);
338 }
339
340 writer.endElement(HTML.TABLE_ELEM);
341 writer.endElement(HTML.TD_ELEM);
342 if (pageDirectionLayout)
343 writer.endElement(HTML.TR_ELEM);
344 writer.endElement(HTML.TABLE_ELEM);
345 }
346
347
348
349
350
351
352
353 protected String getLayout(UISelectMany selectMany) {
354 String layout = super.getLayout(selectMany);
355 if (layout == null) {
356 layout = LINE_DIRECTION;
357 }
358 return layout;
359 }
360
361
362
363
364
365
366
367 protected int getLayoutWidth(UISelectMany selectMany) {
368 String layoutWidthString = null;
369 if (selectMany instanceof HtmlSelectManyCheckbox) {
370 layoutWidthString = ((HtmlSelectManyCheckbox) selectMany).getLayoutWidth();
371 } else {
372 layoutWidthString = (String) selectMany.getAttributes().get(JSFAttr.LAYOUT_WIDTH_ATTR);
373 }
374 final int defaultLayoutWidth = 1;
375 int layoutWidth = defaultLayoutWidth;
376 try {
377 if (layoutWidthString != null && layoutWidthString.trim().length() > 0) {
378 layoutWidth = Integer.parseInt(layoutWidthString);
379 }
380 if (layoutWidth < 1) {
381 layoutWidth = defaultLayoutWidth;
382 }
383 } catch (Exception e) {
384 layoutWidth = defaultLayoutWidth;
385 }
386 return layoutWidth;
387 }
388
389 protected void renderSingleCheckbox(FacesContext facesContext, HtmlCheckbox checkbox) throws IOException
390 {
391 String forAttr = checkbox.getFor();
392 if (forAttr == null)
393 {
394 throw new IllegalStateException("mandatory attribute 'for'");
395 }
396 int index = checkbox.getIndex();
397 if (index < 0)
398 {
399 throw new IllegalStateException("positive index must be given");
400 }
401
402 UIComponent uiComponent = checkbox.findComponent(forAttr);
403 if (uiComponent == null)
404 {
405 throw new IllegalStateException("Could not find component '" + forAttr + "' (calling findComponent on component '" + checkbox.getClientId(facesContext) + "')");
406 }
407 if (!(uiComponent instanceof UISelectMany))
408 {
409 throw new IllegalStateException("UISelectMany expected");
410 }
411
412 UISelectMany uiSelectMany = (UISelectMany)uiComponent;
413 Converter converter = getConverter(facesContext, uiSelectMany);
414 List selectItemList = RendererUtils.getSelectItemList(uiSelectMany);
415 if (index >= selectItemList.size())
416 {
417 throw new IndexOutOfBoundsException("index " + index + " >= " + selectItemList.size());
418 }
419
420 SelectItem selectItem = (SelectItem)selectItemList.get(index);
421 Object itemValue = selectItem.getValue();
422 String itemStrValue = getItemStringValue(facesContext, uiSelectMany, converter, itemValue);
423
424
425 Set lookupSet = RendererUtils.getSubmittedValuesAsSet(facesContext, uiComponent, converter, uiSelectMany);
426
427 boolean useSubmittedValues = (lookupSet != null);
428 if (!useSubmittedValues)
429 {
430 lookupSet = RendererUtils.getSelectedValuesAsSet(facesContext, uiComponent, converter, uiSelectMany);
431 }
432
433 ResponseWriter writer = facesContext.getResponseWriter();
434
435
436
437
438
439
440
441
442 String itemId = renderCheckbox(facesContext,
443 uiSelectMany,
444 itemStrValue,
445 isDisabled(facesContext,uiSelectMany),
446 lookupSet.contains(itemStrValue), false, index);
447
448
449
450 boolean componentDisabled = isDisabled(facesContext, uiSelectMany);
451 boolean itemDisabled = selectItem.isDisabled();
452 boolean disabled = (componentDisabled || itemDisabled);
453
454 HtmlRendererUtils.renderLabel(writer, uiSelectMany, itemId, selectItem.getLabel(), disabled);
455
456 }
457
458
459 protected boolean isDisabled(FacesContext facesContext, UIComponent uiComponent)
460 {
461 if (!UserRoleUtils.isEnabledOnUserRole(uiComponent))
462 {
463 return true;
464 }
465 else
466 {
467 return super.isDisabled(facesContext, uiComponent);
468 }
469 }
470
471 public void decode(FacesContext facesContext, UIComponent uiComponent)
472 {
473 if (uiComponent instanceof HtmlCheckbox)
474 {
475
476 }
477 else
478 {
479 super.decode(facesContext, uiComponent);
480 }
481 }
482
483 protected String getItemStringValue(FacesContext facesContext, UISelectMany selectMany,
484 Converter converter, Object itemValue) {
485 String itemStrValue;
486 if (converter == null)
487 {
488 itemStrValue = itemValue.toString();
489 }
490 else
491 {
492 itemStrValue = converter.getAsString(facesContext, selectMany, itemValue);
493 }
494 return itemStrValue;
495 }
496
497 protected Converter getConverter(FacesContext facesContext,
498 UISelectMany selectMany)
499 {
500 Converter converter;
501 try
502 {
503 converter = RendererUtils.findUISelectManyConverter(facesContext,
504 selectMany);
505 }
506 catch (FacesException e)
507 {
508 log.error("Error finding Converter for component with id "
509 + selectMany.getClientId(facesContext));
510 converter = null;
511 }
512 return converter;
513 }
514
515 }