View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.shared_orchestra.renderkit.html;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.myfaces.shared_orchestra.renderkit.RendererUtils;
24  import org.apache.myfaces.shared_orchestra.renderkit.JSFAttr;
25  import org.apache.myfaces.shared_orchestra.renderkit.html.HTML;
26  import org.apache.myfaces.shared_orchestra.util.ArrayUtils;
27  import org.apache.myfaces.shared_orchestra.util.StringUtils;
28  
29  import javax.faces.context.FacesContext;
30  import javax.faces.context.ResponseWriter;
31  import javax.faces.component.UIComponent;
32  import javax.faces.component.UIPanel;
33  import javax.faces.component.html.HtmlPanelGrid;
34  import java.io.IOException;
35  import java.util.Iterator;
36  
37  /**
38   * @author Martin Marinschek
39   * @version $Revision: 587938 $ $Date: 2007-10-24 12:44:21 -0500 (Wed, 24 Oct 2007) $
40   *          <p/>
41   *          $Log: $
42   */
43  public class HtmlGridRendererBase
44          extends HtmlRenderer
45  {
46      private static final Log log = LogFactory.getLog(HtmlGridRendererBase.class);
47  
48      public boolean getRendersChildren()
49      {
50          return true;
51      }
52  
53      public void encodeBegin(FacesContext facesContext, UIComponent component)
54              throws IOException
55      {
56          // all work done in encodeEnd()
57      }
58  
59      public void encodeChildren(FacesContext context, UIComponent component)
60          throws IOException
61      {
62          // all work done in encodeEnd()
63      }
64  
65      public void encodeEnd(FacesContext facesContext, UIComponent component)
66              throws IOException
67      {
68          RendererUtils.checkParamValidity(facesContext, component, UIPanel.class);
69  
70          int columns;
71          if (component instanceof HtmlPanelGrid)
72          {
73              columns = ((HtmlPanelGrid)component).getColumns();
74          }
75          else
76          {
77              Integer i = (Integer)component.getAttributes().get(org.apache.myfaces.shared_orchestra.renderkit.JSFAttr.COLUMNS_ATTR);
78              columns = i != null ? i.intValue() : 0;
79          }
80  
81          if (columns <= 0)
82          {
83              if (log.isErrorEnabled())
84              {
85                  log.error("Wrong columns attribute for PanelGrid " + component.getClientId(facesContext) + ": " + columns);
86              }
87              columns = 1;
88          }
89  
90          ResponseWriter writer = facesContext.getResponseWriter();
91          writer.startElement(HTML.TABLE_ELEM, component);
92          HtmlRendererUtils.writeIdIfNecessary(writer, component, facesContext);
93          HtmlRendererUtils.renderHTMLAttributes(writer, component, HTML.TABLE_PASSTHROUGH_ATTRIBUTES);
94  
95          writer.flush();
96  
97          // theader and tfooter are rendered before the tbody 
98          renderHeaderOrFooter(facesContext, writer, component, columns, true);   //Header facet
99          renderHeaderOrFooter(facesContext, writer, component, columns, false);  //Footer facet
100         
101         renderChildren(facesContext, writer, component, columns);
102 
103         writer.endElement(HTML.TABLE_ELEM);
104     }
105 
106 
107     protected void renderHeaderOrFooter(FacesContext context,
108                                       ResponseWriter writer,
109                                       UIComponent component,
110                                       int columns,
111                                       boolean header)
112         throws IOException
113     {
114         UIComponent facet = component.getFacet(header ? "header" : "footer");
115         if (facet == null) return;
116 
117         HtmlRendererUtils.writePrettyLineSeparator(context);
118         writer.startElement(header ? org.apache.myfaces.shared_orchestra.renderkit.html.HTML.THEAD_ELEM : HTML.TFOOT_ELEM, component);
119         writer.startElement(HTML.TR_ELEM, component);
120         writer.startElement(header ? HTML.TH_ELEM : HTML.TD_ELEM, component);
121 
122         String styleClass = (component instanceof HtmlPanelGrid)
123             ? (header ?
124                          ((HtmlPanelGrid)component).getHeaderClass() :
125                          ((HtmlPanelGrid)component).getFooterClass())
126             : (header ?
127                          (String)component.getAttributes().get(JSFAttr.HEADER_CLASS_ATTR) :
128                          (String)component.getAttributes().get(org.apache.myfaces.shared_orchestra.renderkit.JSFAttr.FOOTER_CLASS_ATTR));
129         if (styleClass != null)
130         {
131             writer.writeAttribute(HTML.CLASS_ATTR, styleClass,
132                                   header ? JSFAttr.HEADER_CLASS_ATTR : org.apache.myfaces.shared_orchestra.renderkit.JSFAttr.FOOTER_CLASS_ATTR);
133         }
134 
135         if (header)
136         {
137             writer.writeAttribute(HTML.SCOPE_ATTR, HTML.SCOPE_COLGROUP_VALUE, null);
138         }
139 
140         writer.writeAttribute(HTML.COLSPAN_ATTR, Integer.toString(columns), null);
141 
142         HtmlRendererUtils.writePrettyLineSeparator(context);
143         RendererUtils.renderChild(context, facet);
144 
145         HtmlRendererUtils.writePrettyLineSeparator(context);
146         writer.endElement(header ? HTML.TH_ELEM : HTML.TD_ELEM);
147         writer.endElement(HTML.TR_ELEM);
148         writer.endElement(header ? HTML.THEAD_ELEM : HTML.TFOOT_ELEM);
149     }
150 
151     protected int childAttributes(FacesContext context,
152             ResponseWriter writer,
153             UIComponent component,
154             int columnIndex)
155         throws IOException
156     {
157         // subclasses can override this method to add attributes to the table cell <td> tag
158         return columnIndex;
159     }
160 
161     protected void renderChildren(FacesContext context,
162                                 ResponseWriter writer,
163                                 UIComponent component,
164                                 int columns)
165         throws IOException
166     {
167         writer.startElement(HTML.TBODY_ELEM, component);
168 
169         String columnClasses;
170         String rowClasses;
171         if (component instanceof HtmlPanelGrid)
172         {
173             columnClasses = ((HtmlPanelGrid)component).getColumnClasses();
174             rowClasses =  ((HtmlPanelGrid)component).getRowClasses();
175         }
176         else
177         {
178             columnClasses = (String)component.getAttributes().get(org.apache.myfaces.shared_orchestra.renderkit.JSFAttr.COLUMN_CLASSES_ATTR);
179             rowClasses = (String)component.getAttributes().get(JSFAttr.ROW_CLASSES_ATTR);
180         }
181 
182         String[] columnClassesArray = (columnClasses == null)
183             ? ArrayUtils.EMPTY_STRING_ARRAY
184             : StringUtils.trim(StringUtils.splitShortString(columnClasses, ','));
185         int columnClassesCount = columnClassesArray.length;
186 
187         String[] rowClassesArray = (rowClasses == null)
188             ? org.apache.myfaces.shared_orchestra.util.ArrayUtils.EMPTY_STRING_ARRAY
189             : StringUtils.trim(StringUtils.splitShortString(rowClasses, ','));
190         int rowClassesCount = rowClassesArray.length;
191 
192         int childCount = getChildCount(component);
193         if (childCount > 0)
194         {
195             int columnIndex = 0;
196             int rowClassIndex = 0;
197             boolean rowStarted = false;
198             for (Iterator it = getChildren(component).iterator(); it.hasNext(); )
199             {
200                 UIComponent child = (UIComponent)it.next();
201                 if (child.isRendered())
202                 {
203                     if (columnIndex == 0)
204                     {
205                         //start of new/next row
206                         if (rowStarted)
207                         {
208                             //do we have to close the last row?
209                             writer.endElement(HTML.TR_ELEM);
210                             HtmlRendererUtils.writePrettyLineSeparator(context);
211                         }
212                         writer.startElement(HTML.TR_ELEM, component);
213                         if (rowClassIndex < rowClassesCount) {
214                             writer.writeAttribute(HTML.CLASS_ATTR, rowClassesArray[rowClassIndex], null);
215                         }
216                         rowStarted = true;
217                         rowClassIndex++;
218                         if (rowClassIndex == rowClassesCount) {
219                             rowClassIndex = 0;
220                         }
221                     }
222 
223                     writer.startElement(HTML.TD_ELEM, component);
224                     if (columnIndex < columnClassesCount)
225                     {
226                         writer.writeAttribute(HTML.CLASS_ATTR, columnClassesArray[columnIndex], null);
227                     }
228                     columnIndex = childAttributes(context, writer, child, columnIndex);
229                     RendererUtils.renderChild(context, child);
230                     writer.endElement(HTML.TD_ELEM);
231 
232                     columnIndex++;
233                     if (columnIndex >= columns) {
234                         columnIndex = 0;
235                     }
236                 }
237             }
238 
239             if (rowStarted)
240             {
241                 if (columnIndex > 0)
242                 {
243                     if (log.isWarnEnabled()) log.warn("PanelGrid " + component.getClientId(context) + " has not enough children. Child count should be a multiple of the columns attribute.");
244                     //Render empty columns, so that table is correct
245                     for ( ; columnIndex < columns; columnIndex++)
246                     {
247                         writer.startElement(HTML.TD_ELEM, component);
248                         if (columnIndex < columnClassesCount)
249                         {
250                             writer.writeAttribute(HTML.CLASS_ATTR, columnClassesArray[columnIndex], null);
251                         }
252                         writer.endElement(HTML.TD_ELEM);
253                     }
254                 }
255                 writer.endElement(HTML.TR_ELEM);
256                 HtmlRendererUtils.writePrettyLineSeparator(context);
257             }
258         }
259 
260         writer.endElement(HTML.TBODY_ELEM);
261     }
262 
263 }