1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.custom.tree.renderkit.html;
20
21 import org.apache.myfaces.renderkit.html.util.AddResource;
22 import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
23 import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
24 import org.apache.myfaces.custom.tree.HtmlTree;
25 import org.apache.myfaces.custom.tree.HtmlTreeColumn;
26 import org.apache.myfaces.custom.tree.HtmlTreeImageCommandLink;
27 import org.apache.myfaces.custom.tree.HtmlTreeNode;
28 import org.apache.myfaces.custom.tree.IconProvider;
29 import org.apache.myfaces.custom.tree.TreeNode;
30 import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
31 import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
32 import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTableRendererBase;
33 import org.apache.myfaces.shared_tomahawk.util.ArrayUtils;
34 import org.apache.myfaces.shared_tomahawk.util.StringUtils;
35
36 import javax.faces.component.UIColumn;
37 import javax.faces.component.UIComponent;
38 import javax.faces.context.FacesContext;
39 import javax.faces.context.ResponseWriter;
40
41 import java.io.IOException;
42 import java.util.ArrayList;
43 import java.util.Iterator;
44 import java.util.List;
45
46
47
48
49
50
51
52
53
54
55 public class HtmlTreeRenderer extends HtmlTableRendererBase
56 {
57
58 private static final String DEFAULT_IMAGE_ICON_LINE = "images/line.gif";
59 private static final String DEFAULT_IMAGE_ICON_NOLINE = "images/noline.gif";
60 private static final String DEFAULT_IMAGE_ICON_CHILD_FIRST = "images/line_first.gif";
61 private static final String DEFAULT_IMAGE_ICON_CHILD_MIDDLE = "images/line_middle.gif";
62 private static final String DEFAULT_IMAGE_ICON_CHILD_LAST = "images/line_last.gif";
63 private static final String DEFAULT_IMAGE_ICON_NODE_OPEN = "images/node_open.gif";
64 private static final String DEFAULT_IMAGE_ICON_NODE_OPEN_FIRST = "images/node_open_first.gif";
65 private static final String DEFAULT_IMAGE_ICON_NODE_OPEN_MIDDLE = "images/node_open_middle.gif";
66 private static final String DEFAULT_IMAGE_ICON_NODE_OPEN_LAST = "images/node_open_last.gif";
67 private static final String DEFAULT_IMAGE_ICON_NODE_CLOSE = "images/node_close.gif";
68 private static final String DEFAULT_IMAGE_ICON_NODE_CLOSE_FIRST = "images/node_close_first.gif";
69 private static final String DEFAULT_IMAGE_ICON_NODE_CLOSE_MIDDLE = "images/node_close_middle.gif";
70 private static final String DEFAULT_IMAGE_ICON_NODE_CLOSE_LAST = "images/node_close_last.gif";
71
72 private static final Integer ZERO = new Integer(0);
73
74 private static final String DEFAULT_IMAGE_ICON_FOLDER = "images/folder.gif";
75
76 public boolean getRendersChildren()
77 {
78 return true;
79 }
80
81 public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException
82 {
83
84 }
85
86 public void encodeChildren(FacesContext facesContext, UIComponent component) throws IOException
87 {
88
89 }
90
91 public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException
92 {
93 RendererUtils.checkParamValidity(facesContext, component, HtmlTree.class);
94 ResponseWriter writer = facesContext.getResponseWriter();
95 HtmlTree tree = (HtmlTree) component;
96
97 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
98 writer.startElement(HTML.TABLE_ELEM, component);
99 HtmlRendererUtils.renderHTMLAttributes(writer, tree, HTML.TABLE_PASSTHROUGH_ATTRIBUTES);
100 writer.writeAttribute(HTML.BORDER_ATTR, ZERO, null);
101 writer.writeAttribute(HTML.CELLSPACING_ATTR, ZERO, null);
102 writer.writeAttribute(HTML.CELLPADDING_ATTR, ZERO, null);
103
104 int maxLevel = tree.getRootNode().getMaxChildLevel();
105
106
107 ArrayList childNodes = new ArrayList(1);
108 childNodes.add(tree.getRootNode());
109
110
111 renderFacet(facesContext, writer, component, true, maxLevel);
112
113
114 renderChildren(facesContext, writer, tree, childNodes, maxLevel, tree.getIconProvider(), component);
115
116
117 renderFacet(facesContext, writer, component, false, maxLevel);
118 writer.endElement(HTML.TABLE_ELEM);
119 }
120
121
122
123
124
125
126
127
128
129
130
131
132
133 protected void renderFacet(FacesContext facesContext, ResponseWriter writer, UIComponent component, boolean header, int maxLevel)
134 throws IOException
135 {
136 int colspan = 0;
137 boolean hasColumnFacet = false;
138 for (Iterator it = component.getChildren().iterator(); it.hasNext();)
139 {
140 UIComponent uiComponent = (UIComponent) it.next();
141 if ((uiComponent.getFamily().equals(UIColumn.COMPONENT_FAMILY))
142 && ((UIColumn) uiComponent).isRendered())
143 {
144 colspan++;
145 if (!hasColumnFacet)
146 {
147 hasColumnFacet = header ? ((UIColumn) uiComponent).getHeader() != null : ((UIColumn) uiComponent)
148 .getFooter() != null;
149 }
150 }
151 else if ((uiComponent.getFamily().equals(HtmlTreeColumn.COMPONENT_FAMILY))
152 && ((HtmlTreeColumn) uiComponent).isRendered())
153 {
154 colspan += maxLevel + 3;
155 if (!hasColumnFacet)
156 {
157 hasColumnFacet = header ? ((UIColumn) uiComponent).getHeader() != null : ((UIColumn) uiComponent)
158 .getFooter() != null;
159 }
160 }
161 }
162
163 UIComponent facet = header ? (UIComponent) component.getFacets().get(HEADER_FACET_NAME)
164 : (UIComponent) component.getFacets().get(FOOTER_FACET_NAME);
165 if (facet != null || hasColumnFacet)
166 {
167
168 String elemName = header ? HTML.THEAD_ELEM : HTML.TFOOT_ELEM;
169
170 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
171 writer.startElement(elemName, component);
172 if (header)
173 {
174 String headerStyleClass = getHeaderClass(component);
175 if (facet != null)
176 renderTableHeaderRow(facesContext, writer, component, facet, headerStyleClass, colspan);
177 if (hasColumnFacet)
178 renderColumnHeaderRow(facesContext, writer, component, headerStyleClass, maxLevel);
179 }
180 else
181 {
182 String footerStyleClass = getFooterClass(component);
183 if (hasColumnFacet)
184 renderColumnFooterRow(facesContext, writer, component, footerStyleClass, maxLevel);
185 if (facet != null)
186 renderTableFooterRow(facesContext, writer, component, facet, footerStyleClass, colspan);
187 }
188 writer.endElement(elemName);
189 }
190 }
191
192 protected void renderColumnHeaderRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
193 String headerStyleClass, int maxLevel) throws IOException
194 {
195 renderColumnHeaderOrFooterRow(facesContext, writer, component, headerStyleClass, true, maxLevel);
196 }
197
198 protected void renderColumnFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
199 String footerStyleClass, int maxLevel) throws IOException
200 {
201 renderColumnHeaderOrFooterRow(facesContext, writer, component, footerStyleClass, false, maxLevel);
202 }
203
204 private void renderColumnHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
205 String styleClass, boolean header, int maxLevel) throws IOException
206 {
207 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
208 writer.startElement(HTML.TR_ELEM, component);
209 for (Iterator it = component.getChildren().iterator(); it.hasNext();)
210 {
211 UIComponent uiComponent = (UIComponent) it.next();
212 if ((uiComponent.getFamily().equals(UIColumn.COMPONENT_FAMILY))
213 && ((UIColumn) uiComponent).isRendered())
214 {
215 if (header)
216 {
217 renderColumnHeaderCell(facesContext, writer, (UIColumn) uiComponent, styleClass, 0);
218 }
219 else
220 {
221 renderColumnFooterCell(facesContext, writer, (UIColumn) uiComponent, styleClass, 0);
222 }
223 }
224 else if ((uiComponent.getFamily().equals(HtmlTreeColumn.COMPONENT_FAMILY))
225 && ((HtmlTreeColumn) uiComponent).isRendered())
226 {
227 if (header)
228 {
229 renderColumnHeaderCell(facesContext, writer, (UIColumn) uiComponent, styleClass, maxLevel + 3);
230 }
231 else
232 {
233 renderColumnFooterCell(facesContext, writer, (UIColumn) uiComponent, styleClass, maxLevel + 3);
234 }
235 }
236 }
237 writer.endElement(HTML.TR_ELEM);
238 }
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253 protected void renderChildren(FacesContext facesContext, ResponseWriter writer, HtmlTree tree, List children,
254 int maxLevel, IconProvider iconProvider, UIComponent component) throws IOException
255 {
256 renderChildren(facesContext, writer, tree, children, maxLevel, iconProvider, 0, component);
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273 protected void renderChildren(FacesContext facesContext, ResponseWriter writer, HtmlTree tree, List children,
274 int maxLevel, IconProvider iconProvider, int rowClassIndex, UIComponent component) throws IOException
275 {
276 String rowClasses = tree.getRowClasses();
277 String columnClasses = tree.getColumnClasses();
278
279 String[] rowClassesArray = (rowClasses == null) ? ArrayUtils.EMPTY_STRING_ARRAY : StringUtils.trim(StringUtils
280 .splitShortString(rowClasses, ','));
281 int rowClassesCount = rowClassesArray.length;
282
283 String[] columnClassesArray = (columnClasses == null) ? ArrayUtils.EMPTY_STRING_ARRAY : StringUtils
284 .trim(StringUtils.splitShortString(columnClasses, ','));
285 int columnClassesCount = columnClassesArray.length;
286 int columnClassIndex = 0;
287
288 for (Iterator it = children.iterator(); it.hasNext();)
289 {
290 HtmlTreeNode child = (HtmlTreeNode) it.next();
291
292 if (!child.isRendered())
293 {
294 continue;
295 }
296 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
297
298 writer.startElement(HTML.TR_ELEM, component);
299
300 if (rowClassIndex < rowClassesCount)
301 {
302 writer.writeAttribute(HTML.CLASS_ATTR, rowClassesArray[rowClassIndex], null);
303 }
304 if (rowClassesCount > 0)
305 {
306 rowClassIndex++;
307 rowClassIndex = rowClassIndex % rowClassesCount;
308 }
309
310 if (null != tree.getVar())
311 {
312 facesContext.getExternalContext().getSessionMap().put(tree.getVar(),
313 ((TreeNode) child.getUserObject()).getUserObject());
314 }
315
316 List componentChildren = tree.getChildren();
317 if ((null != componentChildren) && (componentChildren.size() > 0))
318 {
319 for (int j = 0, size = tree.getChildCount(); j < size; j++)
320 {
321 UIComponent componentChild = (UIComponent) componentChildren.get(j);
322 if ((componentChild.getFamily().equals(UIColumn.COMPONENT_FAMILY))
323 && ((UIColumn) componentChild).isRendered())
324 {
325 writer.startElement(HTML.TD_ELEM, tree);
326 if (columnClassIndex < columnClassesCount)
327 {
328 writer.writeAttribute(HTML.CLASS_ATTR, columnClassesArray[columnClassIndex], null);
329 }
330 if (columnClassesCount > 0)
331 {
332 columnClassIndex++;
333 columnClassIndex = columnClassIndex % columnClassesCount;
334 }
335 RendererUtils.renderChild(facesContext, componentChild);
336 writer.endElement(HTML.TD_ELEM);
337 }
338 else if ((componentChild.getFamily().equals(HtmlTreeColumn.COMPONENT_FAMILY))
339 && ((HtmlTreeColumn) componentChild).isRendered())
340 {
341 renderTreeColumnChild(facesContext, writer, componentChild, tree, child, maxLevel, iconProvider);
342 }
343 }
344 }
345 else
346 {
347 renderTreeColumnChild(facesContext, writer, null, tree, child, maxLevel, iconProvider);
348 }
349
350 writer.endElement(HTML.TR_ELEM);
351
352 if (child.getChildCount() > 0)
353 {
354 renderChildren(facesContext, writer, tree, child.getChildren(), maxLevel, iconProvider, rowClassIndex, component);
355 if (rowClassesCount > 0)
356 {
357 rowClassIndex += (child.getChildCount() % rowClassesCount);
358 rowClassIndex = rowClassIndex % rowClassesCount;
359 }
360 }
361 }
362 }
363
364 public String getDefaultImagePath(FacesContext context, String relativePathInResourceFolder)
365 {
366 AddResource instance = AddResourceFactory.getInstance(context);
367 return instance.getResourceUri(context, HtmlTree.class, relativePathInResourceFolder, false);
368 }
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385 protected void renderTreeColumnChild(FacesContext facesContext, ResponseWriter writer, UIComponent component,
386 HtmlTree tree, HtmlTreeNode child, int maxLevel, IconProvider iconProvider) throws IOException
387 {
388 String iconClass = tree.getIconClass();
389 int[] layout = child.getLayout();
390
391 for (int i = 0; i < layout.length - 1; i++)
392 {
393 int state = layout[i];
394 writer.startElement(HTML.TD_ELEM, child);
395 String url = getLayoutImage(facesContext, tree, state);
396
397 if ((url != null) && (url.length() > 0))
398 {
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422 writeImageElement(url, facesContext, writer, child);
423 }
424 writer.endElement(HTML.TD_ELEM);
425
426 }
427
428
429 writer.startElement(HTML.TD_ELEM, tree);
430 int state = layout[layout.length - 1];
431 String url = getLayoutImage(facesContext, tree, state);
432
433 if (state == HtmlTreeNode.CHILD || state == HtmlTreeNode.CHILD_FIRST || state == HtmlTreeNode.CHILD_LAST)
434 {
435
436 writeImageElement(url, facesContext, writer, child);
437 }
438 else
439 {
440 HtmlTreeImageCommandLink expandCollapse = (HtmlTreeImageCommandLink) child
441 .getExpandCollapseCommand(facesContext);
442 expandCollapse.setImage(getLayoutImage(facesContext, tree, layout[layout.length - 1]));
443
444 expandCollapse.encodeBegin(facesContext);
445 expandCollapse.encodeEnd(facesContext);
446 }
447 writer.endElement(HTML.TD_ELEM);
448
449 int labelColSpan = maxLevel - child.getLevel() + 1;
450
451
452 if (iconProvider != null)
453 {
454 url = iconProvider.getIconUrl(child.getUserObject(), child.getChildCount(), child.isLeaf(facesContext));
455 }
456 else
457 {
458 if (!child.isLeaf(facesContext))
459 {
460
461 url = getDefaultImagePath(facesContext, DEFAULT_IMAGE_ICON_FOLDER );
462 }
463 else
464 {
465 url = null;
466 }
467 }
468
469 if ((url != null) && (url.length() > 0))
470 {
471 writer.startElement(HTML.TD_ELEM, tree);
472 if (iconClass != null)
473 {
474 writer.writeAttribute(HTML.CLASS_ATTR, iconClass, null);
475 }
476 writeImageElement(url, facesContext, writer, child);
477 writer.endElement(HTML.TD_ELEM);
478 }
479 else
480 {
481
482 labelColSpan++;
483 }
484
485
486 writer.startElement(HTML.TD_ELEM, tree);
487 writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(labelColSpan), null);
488 if (child.isSelected() && tree.getSelectedNodeClass() != null)
489 {
490 writer.writeAttribute(HTML.CLASS_ATTR, tree.getSelectedNodeClass(), null);
491 }
492 else if (!child.isSelected() && tree.getNodeClass() != null)
493 {
494 writer.writeAttribute(HTML.CLASS_ATTR, tree.getNodeClass(), null);
495 }
496
497 List componentChildren = null;
498 if (null != component)
499 {
500 componentChildren = component.getChildren();
501 }
502 if ((null != componentChildren) && (componentChildren.size() > 0))
503 {
504 for (int k = 0; k < componentChildren.size(); k++)
505 {
506 UIComponent componentChild = (UIComponent) componentChildren.get(k);
507 RendererUtils.renderChild(facesContext, componentChild);
508 }
509 }
510 else
511 {
512 child.encodeBegin(facesContext);
513 child.encodeEnd(facesContext);
514 }
515 writer.endElement(HTML.TD_ELEM);
516 }
517
518 private void writeImageElement(String url, FacesContext facesContext, ResponseWriter writer, HtmlTreeNode child)
519 throws IOException
520 {
521 writer.startElement(HTML.IMG_ELEM, child);
522 String src = facesContext.getApplication().getViewHandler().getResourceURL(facesContext, url);
523
524
525
526
527
528
529
530
531
532
533
534 writer.writeAttribute(HTML.SRC_ATTR, src, null);
535 writer.writeAttribute(HTML.BORDER_ATTR, ZERO, null);
536
537 HtmlRendererUtils.renderHTMLAttributes(writer, child, HTML.IMG_PASSTHROUGH_ATTRIBUTES);
538
539 writer.endElement(HTML.IMG_ELEM);
540 }
541
542 protected String getLayoutImage(FacesContext context, HtmlTree tree, int state)
543 {
544 switch (state)
545 {
546 case HtmlTreeNode.OPEN:
547 return getImageUrl(context, tree.getIconNodeOpenMiddle(), DEFAULT_IMAGE_ICON_NODE_OPEN_MIDDLE);
548 case HtmlTreeNode.OPEN_FIRST:
549 return getImageUrl(context, tree.getIconNodeOpenFirst(), DEFAULT_IMAGE_ICON_NODE_OPEN_FIRST);
550 case HtmlTreeNode.OPEN_LAST:
551 return getImageUrl(context, tree.getIconNodeOpenLast(), DEFAULT_IMAGE_ICON_NODE_OPEN_LAST);
552 case HtmlTreeNode.OPEN_SINGLE:
553 return getImageUrl(context, tree.getIconNodeOpen(), DEFAULT_IMAGE_ICON_NODE_OPEN);
554 case HtmlTreeNode.CLOSED:
555 return getImageUrl(context, tree.getIconNodeCloseMiddle(), DEFAULT_IMAGE_ICON_NODE_CLOSE_MIDDLE);
556 case HtmlTreeNode.CLOSED_FIRST:
557 return getImageUrl(context, tree.getIconNodeCloseFirst(), DEFAULT_IMAGE_ICON_NODE_CLOSE_FIRST);
558 case HtmlTreeNode.CLOSED_LAST:
559 return getImageUrl(context, tree.getIconNodeCloseLast(), DEFAULT_IMAGE_ICON_NODE_CLOSE_LAST);
560 case HtmlTreeNode.CLOSED_SINGLE:
561 return getImageUrl(context, tree.getIconNodeClose(), DEFAULT_IMAGE_ICON_NODE_CLOSE);
562 case HtmlTreeNode.CHILD:
563 return getImageUrl(context, tree.getIconChildMiddle(), DEFAULT_IMAGE_ICON_CHILD_MIDDLE);
564 case HtmlTreeNode.CHILD_FIRST:
565 return getImageUrl(context, tree.getIconChildFirst(), DEFAULT_IMAGE_ICON_CHILD_FIRST);
566 case HtmlTreeNode.CHILD_LAST:
567 return getImageUrl(context, tree.getIconChildLast(), DEFAULT_IMAGE_ICON_CHILD_LAST);
568 case HtmlTreeNode.LINE:
569 return getImageUrl(context, tree.getIconLine(), DEFAULT_IMAGE_ICON_LINE);
570 case HtmlTreeNode.EMPTY:
571 return getImageUrl(context, tree.getIconNoline(), DEFAULT_IMAGE_ICON_NOLINE);
572 default:
573 return getImageUrl(context, tree.getIconNoline(), DEFAULT_IMAGE_ICON_NOLINE);
574 }
575 }
576
577 protected String getImageUrl(FacesContext context, String userValue, String resourceValue)
578 {
579 AddResource addResource = AddResourceFactory.getInstance(context);
580 if(userValue != null)
581 {
582 return addResource.getResourceUri(context, userValue, false);
583 }
584 return addResource.getResourceUri(context, HtmlTree.class, resourceValue, false);
585 }
586 }