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.NamingContainer;
35 import javax.faces.component.UIComponent;
36 import javax.faces.component.UISelectMany;
37 import javax.faces.component.UISelectBoolean;
38 import javax.faces.context.FacesContext;
39 import javax.faces.context.ResponseWriter;
40 import javax.faces.convert.Converter;
41 import javax.faces.model.SelectItem;
42 import javax.faces.model.SelectItemGroup;
43
44 import java.io.IOException;
45 import java.util.List;
46 import java.util.Set;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 public class HtmlCheckboxRenderer
69 extends HtmlCheckboxRendererBase
70 {
71 private static final Log log = LogFactory.getLog(HtmlCheckboxRenderer.class);
72
73 private static final String PAGE_DIRECTION = "pageDirection";
74
75 private static final String LINE_DIRECTION = "lineDirection";
76
77 private static final String LAYOUT_SPREAD = "spread";
78
79 public void encodeEnd(FacesContext context, UIComponent component) throws IOException
80 {
81 if (context == null) throw new NullPointerException("context");
82 if (component == null) throw new NullPointerException("component");
83
84 if (component instanceof HtmlCheckbox)
85 {
86 renderSingleCheckbox(context, (HtmlCheckbox)component);
87 }
88 else if (component instanceof DisplayValueOnlyCapable && HtmlRendererUtils.isDisplayValueOnly(component))
89 {
90 HtmlRendererUtils.renderDisplayValueOnlyForSelects(context, component);
91 }
92 else if (component instanceof UISelectMany)
93 {
94 String layout = getLayout((UISelectMany)component);
95 if (layout != null && layout.equals(LAYOUT_SPREAD))
96 {
97 return;
98 }
99 else
100 {
101 super.encodeEnd(context, component);
102 }
103 }
104 else if(component instanceof UISelectBoolean)
105 {
106 super.encodeEnd(context,component);
107 }
108 else
109 {
110 throw new IllegalArgumentException("Unsupported component class " + component.getClass().getName());
111 }
112 }
113
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, selectItem
280 .getLabel(), disabled, checked, false);
281 writer.endElement(HTML.LABEL_ELEM);
282 }
283 }
284
285 protected void renderLabelClassIfNecessary(FacesContext facesContext,
286 UISelectMany selectMany, boolean disabled) throws IOException
287 {
288 String labelClass = null;
289 boolean componentDisabled = isDisabled(facesContext, selectMany);
290 if (componentDisabled || disabled)
291 {
292 labelClass = (String) selectMany.getAttributes().get(
293 JSFAttr.DISABLED_CLASS_ATTR);
294 }
295 else
296 {
297 labelClass = (String) selectMany.getAttributes().get(
298 JSFAttr.ENABLED_CLASS_ATTR);
299 }
300 if (labelClass != null)
301 {
302 ResponseWriter writer = facesContext.getResponseWriter();
303 writer.writeAttribute("class", labelClass, "labelClass");
304 }
305 }
306
307 protected void renderCheckboxGroup(FacesContext facesContext,
308 UIComponent uiComponent, SelectItemGroup selectItemGroup,
309 boolean useSubmittedValues, Set lookupSet,
310 Converter converter, boolean pageDirectionLayout) throws IOException {
311 ResponseWriter writer = facesContext.getResponseWriter();
312 UISelectMany selectMany = (UISelectMany)uiComponent;
313 writer.startElement(HTML.TABLE_ELEM, selectMany);
314 if (pageDirectionLayout)
315 writer.startElement(HTML.TR_ELEM, selectMany);
316 writer.startElement(HTML.TD_ELEM, selectMany);
317 writer.write(selectItemGroup.getLabel());
318 writer.endElement(HTML.TD_ELEM);
319
320 if (pageDirectionLayout) {
321 writer.endElement(HTML.TR_ELEM);
322 writer.startElement(HTML.TR_ELEM, selectMany);
323 }
324 writer.startElement(HTML.TD_ELEM, selectMany);
325 writer.startElement(HTML.TABLE_ELEM, selectMany);
326 writer.writeAttribute(HTML.BORDER_ATTR, "0", null);
327
328 SelectItem[] selectItems = selectItemGroup.getSelectItems();
329 for (int i=0; i<selectItems.length; i++) {
330 renderGroupOrItemCheckbox(facesContext, selectMany, selectItems[i], useSubmittedValues, lookupSet, converter, pageDirectionLayout);
331 }
332
333 writer.endElement(HTML.TABLE_ELEM);
334 writer.endElement(HTML.TD_ELEM);
335 if (pageDirectionLayout)
336 writer.endElement(HTML.TR_ELEM);
337 writer.endElement(HTML.TABLE_ELEM);
338 }
339
340
341
342
343
344
345
346 protected String getLayout(UISelectMany selectMany) {
347 String layout = super.getLayout(selectMany);
348 if (layout == null) {
349 layout = LINE_DIRECTION;
350 }
351 return layout;
352 }
353
354
355
356
357
358
359
360 protected int getLayoutWidth(UISelectMany selectMany) {
361 String layoutWidthString = null;
362 if (selectMany instanceof HtmlSelectManyCheckbox) {
363 layoutWidthString = ((HtmlSelectManyCheckbox) selectMany).getLayoutWidth();
364 } else {
365 layoutWidthString = (String) selectMany.getAttributes().get(JSFAttr.LAYOUT_WIDTH_ATTR);
366 }
367 final int defaultLayoutWidth = 1;
368 int layoutWidth = defaultLayoutWidth;
369 try {
370 if (layoutWidthString != null && layoutWidthString.trim().length() > 0) {
371 layoutWidth = Integer.parseInt(layoutWidthString);
372 }
373 if (layoutWidth < 1) {
374 layoutWidth = defaultLayoutWidth;
375 }
376 } catch (Exception e) {
377 layoutWidth = defaultLayoutWidth;
378 }
379 return layoutWidth;
380 }
381
382 protected void renderSingleCheckbox(FacesContext facesContext, HtmlCheckbox checkbox) throws IOException
383 {
384 String forAttr = checkbox.getFor();
385 if (forAttr == null)
386 {
387 throw new IllegalStateException("mandatory attribute 'for'");
388 }
389 int index = checkbox.getIndex();
390 if (index < 0)
391 {
392 throw new IllegalStateException("positive index must be given");
393 }
394
395 UIComponent uiComponent = checkbox.findComponent(forAttr);
396 if (uiComponent == null)
397 {
398 throw new IllegalStateException("Could not find component '" + forAttr + "' (calling findComponent on component '" + checkbox.getClientId(facesContext) + "')");
399 }
400 if (!(uiComponent instanceof UISelectMany))
401 {
402 throw new IllegalStateException("UISelectMany expected");
403 }
404
405 UISelectMany uiSelectMany = (UISelectMany)uiComponent;
406 Converter converter = getConverter(facesContext, uiSelectMany);
407 List selectItemList = RendererUtils.getSelectItemList(uiSelectMany);
408 if (index >= selectItemList.size())
409 {
410 throw new IndexOutOfBoundsException("index " + index + " >= " + selectItemList.size());
411 }
412
413 SelectItem selectItem = (SelectItem)selectItemList.get(index);
414 Object itemValue = selectItem.getValue();
415 String itemStrValue = getItemStringValue(facesContext, uiSelectMany, converter, itemValue);
416
417
418 Set lookupSet = RendererUtils.getSubmittedValuesAsSet(facesContext, uiComponent, converter, uiSelectMany);
419
420 boolean useSubmittedValues = (lookupSet != null);
421 if (!useSubmittedValues)
422 {
423 lookupSet = RendererUtils.getSelectedValuesAsSet(facesContext, uiComponent, converter, uiSelectMany);
424 }
425
426 ResponseWriter writer = facesContext.getResponseWriter();
427
428 writer.startElement(HTML.LABEL_ELEM, uiSelectMany);
429
430 renderCheckbox(facesContext,
431 uiSelectMany,
432 itemStrValue,
433 selectItem.getLabel(),
434 isDisabled(facesContext,uiSelectMany),
435 lookupSet.contains(itemStrValue), false,
436 index);
437
438 writer.endElement(HTML.LABEL_ELEM);
439 }
440
441
442
443
444
445 protected String renderCheckbox(FacesContext facesContext,
446 UIComponent uiComponent, String value, String label,
447 boolean disabled, boolean checked, boolean renderId, int itemNum) throws IOException {
448 String clientId = uiComponent.getClientId(facesContext);
449
450 String itemId = clientId + NamingContainer.SEPARATOR_CHAR + itemNum;
451
452 ResponseWriter writer = facesContext.getResponseWriter();
453
454 writer.startElement(HTML.INPUT_ELEM, uiComponent);
455
456 if (itemId != null)
457 {
458 writer.writeAttribute(HTML.ID_ATTR, itemId, null);
459 }
460 writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_CHECKBOX, null);
461 writer.writeAttribute(HTML.NAME_ATTR, clientId, null);
462
463 if (renderId) {
464 HtmlRendererUtils.writeIdIfNecessary(writer, uiComponent, facesContext);
465 }
466
467 if (checked) {
468 writer.writeAttribute(HTML.CHECKED_ATTR, org.apache.myfaces.shared_tomahawk.renderkit.html.HTML.CHECKED_ATTR, null);
469 }
470
471 if (disabled) {
472 writer.writeAttribute(HTML.DISABLED_ATTR, HTML.DISABLED_ATTR, null);
473 }
474
475 if ((value != null) && (value.length() > 0)) {
476 writer.writeAttribute(HTML.VALUE_ATTR, value, null);
477 }
478
479 if (uiComponent instanceof UISelectBoolean)
480 {
481 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent,
482 HTML.INPUT_PASSTHROUGH_ATTRIBUTES_WITHOUT_DISABLED);
483 }
484 else
485 {
486
487
488 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.INPUT_ATTRIBUTES);
489 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.COMMON_PASSTROUGH_ATTRIBUTES_WITHOUT_STYLE);
490 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.COMMON_FIELD_ATTRIBUTES_WITHOUT_DISABLED);
491 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.COMMON_FIELD_EVENT_ATTRIBUTES);
492 }
493 if (isDisabled(facesContext, uiComponent)) {
494 writer.writeAttribute(HTML.DISABLED_ATTR, Boolean.TRUE, null);
495 }
496
497 writer.endElement(HTML.INPUT_ELEM);
498
499 if ((label != null) && (label.length() > 0)) {
500 writer.write(HTML.NBSP_ENTITY);
501 writer.writeText(label, null);
502 }
503
504 return itemId;
505 }
506
507 protected boolean isDisabled(FacesContext facesContext, UIComponent uiComponent)
508 {
509 if (!UserRoleUtils.isEnabledOnUserRole(uiComponent))
510 {
511 return true;
512 }
513 else
514 {
515 return super.isDisabled(facesContext, uiComponent);
516 }
517 }
518
519 public void decode(FacesContext facesContext, UIComponent uiComponent)
520 {
521 if (uiComponent instanceof HtmlCheckbox)
522 {
523
524 }
525 else
526 {
527 super.decode(facesContext, uiComponent);
528 }
529 }
530
531 protected String getItemStringValue(FacesContext facesContext, UISelectMany selectMany,
532 Converter converter, Object itemValue) {
533 String itemStrValue;
534 if (converter == null)
535 {
536 itemStrValue = itemValue.toString();
537 }
538 else
539 {
540 itemStrValue = converter.getAsString(facesContext, selectMany, itemValue);
541 }
542 return itemStrValue;
543 }
544
545 protected Converter getConverter(FacesContext facesContext,
546 UISelectMany selectMany)
547 {
548 Converter converter;
549 try
550 {
551 converter = RendererUtils.findUISelectManyConverter(facesContext,
552 selectMany);
553 }
554 catch (FacesException e)
555 {
556 log.error("Error finding Converter for component with id "
557 + selectMany.getClientId(facesContext));
558 converter = null;
559 }
560 return converter;
561 }
562
563 }