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