Source code: org/apache/myfaces/renderkit/html/HtmlGridRendererBase.java
1 /**
2 * Copyright 2004 by Irian Marinschek & Spiegl Software OEG
3 */
4 package org.apache.myfaces.renderkit.html;
5
6 import org.apache.commons.logging.Log;
7 import org.apache.commons.logging.LogFactory;
8 import org.apache.myfaces.renderkit.RendererUtils;
9 import org.apache.myfaces.renderkit.JSFAttr;
10 import org.apache.myfaces.util.ArrayUtils;
11 import org.apache.myfaces.util.StringUtils;
12
13 import javax.faces.context.FacesContext;
14 import javax.faces.context.ResponseWriter;
15 import javax.faces.component.UIComponent;
16 import javax.faces.component.UIPanel;
17 import javax.faces.component.html.HtmlPanelGrid;
18 import java.io.IOException;
19 import java.util.Iterator;
20
21 /**
22 * @author Martin Marinschek
23 * @version $Revision: $ $Date: $
24 * <p/>
25 * $Log: $
26 */
27 public class HtmlGridRendererBase
28 extends HtmlRenderer
29 {
30 private static final Log log = LogFactory.getLog(HtmlGridRendererBase.class);
31
32 public boolean getRendersChildren()
33 {
34 return true;
35 }
36
37 public void encodeBegin(FacesContext facesContext, UIComponent component)
38 throws IOException
39 {
40 // all work done in encodeEnd()
41 }
42
43 public void encodeChildren(FacesContext context, UIComponent component)
44 throws IOException
45 {
46 // all work done in encodeEnd()
47 }
48
49 public void encodeEnd(FacesContext facesContext, UIComponent component)
50 throws IOException
51 {
52 RendererUtils.checkParamValidity(facesContext, component, UIPanel.class);
53
54 int columns;
55 if (component instanceof HtmlPanelGrid)
56 {
57 columns = ((HtmlPanelGrid)component).getColumns();
58 }
59 else
60 {
61 Integer i = (Integer)component.getAttributes().get(JSFAttr.COLUMNS_ATTR);
62 columns = i != null ? i.intValue() : 0;
63 }
64
65 if (columns <= 0)
66 {
67 if (log.isErrorEnabled())
68 {
69 log.error("Wrong columns attribute for PanelGrid " + component.getClientId(facesContext) + ": " + columns);
70 }
71 columns = 1;
72 }
73
74 ResponseWriter writer = facesContext.getResponseWriter();
75 writer.startElement(HTML.TABLE_ELEM, component);
76 HtmlRendererUtils.writeIdIfNecessary(writer, component, facesContext);
77 HtmlRendererUtils.renderHTMLAttributes(writer, component, HTML.TABLE_PASSTHROUGH_ATTRIBUTES);
78
79 writer.flush();
80
81 // theader and tfooter are rendered before the tbody
82 renderHeaderOrFooter(facesContext, writer, component, columns, true); //Header facet
83 renderHeaderOrFooter(facesContext, writer, component, columns, false); //Footer facet
84
85 renderChildren(facesContext, writer, component, columns);
86
87 writer.endElement(HTML.TABLE_ELEM);
88 }
89
90
91 private void renderHeaderOrFooter(FacesContext context,
92 ResponseWriter writer,
93 UIComponent component,
94 int columns,
95 boolean header)
96 throws IOException
97 {
98 UIComponent facet = component.getFacet(header ? "header" : "footer");
99 if (facet == null) return;
100
101 HtmlRendererUtils.writePrettyLineSeparator(context);
102 writer.startElement(header ? HTML.THEAD_ELEM : HTML.TFOOT_ELEM, component);
103 writer.startElement(HTML.TR_ELEM, component);
104 writer.startElement(header ? HTML.TH_ELEM : HTML.TD_ELEM, component);
105
106 String styleClass = (component instanceof HtmlPanelGrid)
107 ? (header ?
108 ((HtmlPanelGrid)component).getHeaderClass() :
109 ((HtmlPanelGrid)component).getFooterClass())
110 : (header ?
111 (String)component.getAttributes().get(JSFAttr.HEADER_CLASS_ATTR) :
112 (String)component.getAttributes().get(JSFAttr.FOOTER_CLASS_ATTR));
113 if (styleClass != null)
114 {
115 writer.writeAttribute(HTML.CLASS_ATTR, styleClass,
116 header ? JSFAttr.HEADER_CLASS_ATTR : JSFAttr.FOOTER_CLASS_ATTR);
117 }
118
119 if (header)
120 {
121 writer.writeAttribute(HTML.SCOPE_ATTR, HTML.SCOPE_COLGROUP_VALUE, null);
122 }
123
124 writer.writeAttribute(HTML.COLSPAN_ATTR, Integer.toString(columns), null);
125
126 HtmlRendererUtils.writePrettyLineSeparator(context);
127 RendererUtils.renderChild(context, facet);
128
129 HtmlRendererUtils.writePrettyLineSeparator(context);
130 writer.endElement(header ? HTML.TH_ELEM : HTML.TD_ELEM);
131 writer.endElement(HTML.TR_ELEM);
132 writer.endElement(header ? HTML.THEAD_ELEM : HTML.TFOOT_ELEM);
133 }
134
135
136 private void renderChildren(FacesContext context,
137 ResponseWriter writer,
138 UIComponent component,
139 int columns)
140 throws IOException
141 {
142 writer.startElement(HTML.TBODY_ELEM, component);
143
144 String columnClasses;
145 String rowClasses;
146 if (component instanceof HtmlPanelGrid)
147 {
148 columnClasses = ((HtmlPanelGrid)component).getColumnClasses();
149 rowClasses = ((HtmlPanelGrid)component).getRowClasses();
150 }
151 else
152 {
153 columnClasses = (String)component.getAttributes().get(JSFAttr.COLUMN_CLASSES_ATTR);
154 rowClasses = (String)component.getAttributes().get(JSFAttr.ROW_CLASSES_ATTR);
155 }
156
157 String[] columnClassesArray = (columnClasses == null)
158 ? ArrayUtils.EMPTY_STRING_ARRAY
159 : StringUtils.trim(StringUtils.splitShortString(columnClasses, ','));
160 int columnClassesCount = columnClassesArray.length;
161
162 String[] rowClassesArray = (rowClasses == null)
163 ? ArrayUtils.EMPTY_STRING_ARRAY
164 : StringUtils.trim(StringUtils.splitShortString(rowClasses, ','));
165 int rowClassesCount = rowClassesArray.length;
166
167 int childCount = component.getChildCount();
168 if (childCount > 0)
169 {
170 int columnIndex = 0;
171 int rowClassIndex = 0;
172 boolean rowStarted = false;
173 for (Iterator it = component.getChildren().iterator(); it.hasNext(); )
174 {
175 UIComponent child = (UIComponent)it.next();
176 if (child.isRendered())
177 {
178 if (columnIndex == 0)
179 {
180 //start of new/next row
181 if (rowStarted)
182 {
183 //do we have to close the last row?
184 writer.endElement(HTML.TR_ELEM);
185 HtmlRendererUtils.writePrettyLineSeparator(context);
186 }
187 writer.startElement(HTML.TR_ELEM, component);
188 if (rowClassIndex < rowClassesCount) {
189 writer.writeAttribute(HTML.CLASS_ATTR, rowClassesArray[rowClassIndex], null);
190 }
191 rowStarted = true;
192 rowClassIndex++;
193 if (rowClassIndex == rowClassesCount) {
194 rowClassIndex = 0;
195 }
196 }
197
198 writer.startElement(HTML.TD_ELEM, component);
199 if (columnIndex < columnClassesCount)
200 {
201 writer.writeAttribute(HTML.CLASS_ATTR, columnClassesArray[columnIndex], null);
202 }
203 RendererUtils.renderChild(context, child);
204 writer.endElement(HTML.TD_ELEM);
205
206 columnIndex++;
207 if (columnIndex >= columns) {
208 columnIndex = 0;
209 }
210 }
211 }
212
213 if (rowStarted)
214 {
215 if (columnIndex > 0)
216 {
217 if (log.isWarnEnabled()) log.warn("PanelGrid " + component.getClientId(context) + " has not enough children. Child count should be a multiple of the columns attribute.");
218 //Render empty columns, so that table is correct
219 for ( ; columnIndex < columns; columnIndex++)
220 {
221 writer.startElement(HTML.TD_ELEM, component);
222 if (columnIndex < columnClassesCount)
223 {
224 writer.writeAttribute(HTML.CLASS_ATTR, columnClassesArray[columnIndex], null);
225 }
226 writer.endElement(HTML.TD_ELEM);
227 }
228 }
229 writer.endElement(HTML.TR_ELEM);
230 HtmlRendererUtils.writePrettyLineSeparator(context);
231 }
232 }
233
234 writer.endElement(HTML.TBODY_ELEM);
235 }
236
237 }