You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2012/03/30 03:13:06 UTC

svn commit: r1307200 - in /myfaces/core/trunk: impl/src/test/java/org/apache/myfaces/renderkit/html/HtmlTableRendererTest.java shared/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlTableRendererBase.java

Author: lu4242
Date: Fri Mar 30 01:13:06 2012
New Revision: 1307200

URL: http://svn.apache.org/viewvc?rev=1307200&view=rev
Log:
MYFACES-3518 and MYFACES-1528 Regression: <h:DataTable> empty with CachedRowSet

Modified:
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/renderkit/html/HtmlTableRendererTest.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlTableRendererBase.java

Modified: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/renderkit/html/HtmlTableRendererTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/renderkit/html/HtmlTableRendererTest.java?rev=1307200&r1=1307199&r2=1307200&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/renderkit/html/HtmlTableRendererTest.java (original)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/renderkit/html/HtmlTableRendererTest.java Fri Mar 30 01:13:06 2012
@@ -19,18 +19,23 @@
 package org.apache.myfaces.renderkit.html;
 
 import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
 
+import javax.faces.component.UIColumn;
 import javax.faces.component.behavior.AjaxBehavior;
 import javax.faces.component.html.HtmlDataTable;
+import javax.faces.component.html.HtmlOutputText;
+import javax.faces.model.ListDataModel;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
-import org.apache.myfaces.test.utils.HtmlCheckAttributesUtil;
-import org.apache.myfaces.test.utils.HtmlRenderedAttr;
 import org.apache.myfaces.test.base.AbstractJsfTestCase;
 import org.apache.myfaces.test.mock.MockRenderKitFactory;
 import org.apache.myfaces.test.mock.MockResponseWriter;
+import org.apache.myfaces.test.utils.HtmlCheckAttributesUtil;
+import org.apache.myfaces.test.utils.HtmlRenderedAttr;
 
 /**
  * @author Bruno Aranda (latest modification by $Author$)
@@ -64,7 +69,13 @@ public class HtmlTableRendererTest exten
                 dataTable.getFamily(),
                 dataTable.getRendererType(),
                 new HtmlTableRenderer());
-        
+
+        HtmlOutputText text = new HtmlOutputText();
+        facesContext.getRenderKit().addRenderer(
+                text.getFamily(),
+                text.getRendererType(),
+                new HtmlTextRenderer());
+
         facesContext.getAttributes().put("org.apache.myfaces.RENDERED_JSF_JS", Boolean.TRUE);
     }
 
@@ -116,4 +127,128 @@ public class HtmlTableRendererTest exten
         }
         
     }
+    
+    /**
+     * Check table renderer behavior when DataModel returns -1 from getRowCount(). It should
+     * render the same as if that value is provided. Note t:dataTable newspaper mode requires
+     * row count to calculate newspaperRows and newspaperColumns. 
+     */
+    public void testNoRowCountRender()
+    {
+        List<Person> list = new ArrayList<Person>();
+        list.add(new Person("John"  , "Smith"));
+        list.add(new Person("Pepito", "Perez"));
+        list.add(new Person("Kurt",   "Kobain"));
+        
+        dataTable.setId("data");
+        dataTable.setRowClasses("class1, class2");
+        dataTable.setVar("person");
+        
+        UIColumn column1 = new UIColumn();
+        HtmlOutputText text = new HtmlOutputText();
+        text.setValueExpression("value", 
+                facesContext.getApplication().getExpressionFactory().createValueExpression(
+                        facesContext.getELContext(), "#{person.firstName}", String.class));
+        column1.getChildren().add(text);
+        
+        dataTable.getChildren().add(column1);
+        UIColumn column2 = new UIColumn();
+        HtmlOutputText text2 = new HtmlOutputText();
+        text2.setValueExpression("value", 
+                facesContext.getApplication().getExpressionFactory().createValueExpression(
+                        facesContext.getELContext(), "#{person.lastName}", String.class));
+        column2.getChildren().add(text2);
+        dataTable.getChildren().add(column2);
+
+        dataTable.setValue(new UnknownRowCountDemoDataModel<Person>(list));
+
+        String output1 = null;
+        try 
+        {
+            dataTable.encodeAll(facesContext);
+            output1 = ((StringWriter) writer.getWriter()).getBuffer().toString();
+        }
+        catch (Exception e)
+        {
+            fail(e.getMessage());
+        }
+        
+        dataTable.setValue(new ListDataModel<Person>(list));
+        ((StringWriter) writer.getWriter()).getBuffer().setLength(0);
+        
+        String output2 = null;
+        try 
+        {
+            dataTable.encodeAll(facesContext);
+            output2 = ((StringWriter) writer.getWriter()).getBuffer().toString();
+        }
+        catch (Exception e)
+        {
+            fail(e.getMessage());
+        }
+        
+        assertTrue(output2.contains("John"));
+        assertTrue(output2.contains("Smith"));
+        assertTrue(output2.contains("class1"));
+        assertTrue(output2.contains("class2"));
+        
+        assertTrue(output1.contains("John"));
+        assertTrue(output1.contains("Smith"));
+        assertTrue(output1.contains("class1"));
+        assertTrue(output1.contains("class2"));
+        
+        assertEquals(output2, output1);
+    }
+
+    public class Person
+    {
+        private String firstName;
+        
+        private String lastName;
+        
+        public Person(String firstName, String lastName)
+        {
+            this.firstName = firstName;
+            this.lastName = lastName;
+        }
+        
+        public String getFirstName()
+        {
+            return firstName;
+        }
+        
+        public void setFirstName(String firstName)
+        {
+            this.firstName = firstName;
+        }
+        
+        public String getLastName()
+        {
+            return lastName;
+        }
+        
+        public void setLastName(String lastName)
+        {
+            this.lastName = lastName;
+        }
+    }
+    
+    public class UnknownRowCountDemoDataModel<E> extends ListDataModel<E>
+    {
+        public UnknownRowCountDemoDataModel()
+        {
+            super();
+        }
+
+        public UnknownRowCountDemoDataModel(List<E> list)
+        {
+            super(list);
+        }
+        
+        @Override
+        public int getRowCount()
+        {
+            return -1;
+        }
+    }
 }

Modified: myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlTableRendererBase.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlTableRendererBase.java?rev=1307200&r1=1307199&r2=1307200&view=diff
==============================================================================
--- myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlTableRendererBase.java (original)
+++ myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlTableRendererBase.java Fri Mar 30 01:13:06 2012
@@ -327,6 +327,29 @@ public class HtmlTableRendererBase exten
         }
     }
 
+    private Integer[] getBodyRows(FacesContext facesContext, UIComponent component)
+    {
+        Integer[] bodyrows = null;
+        String bodyrowsAttr = (String) component.getAttributes().get(JSFAttr.BODYROWS_ATTR);
+        if(bodyrowsAttr != null && !"".equals(bodyrowsAttr)) 
+        {   
+            String[] bodyrowsString = StringUtils.trim(StringUtils.splitShortString(bodyrowsAttr, ','));
+            // parsing with no exception handling, because of JSF-spec: 
+            // "If present, this must be a comma separated list of integers."
+            bodyrows = new Integer[bodyrowsString.length];
+            for(int i = 0; i < bodyrowsString.length; i++) 
+            {
+                bodyrows[i] = new Integer(bodyrowsString[i]);
+            }
+            
+        }
+        else
+        {
+            bodyrows = ZERO_INT_ARRAY;
+        }
+        return bodyrows;
+    }
+
     /**
      * Renders everything inside the TBODY tag by iterating over the row objects
      * between offsets first and first+rows and applying the UIColumn components
@@ -337,12 +360,19 @@ public class HtmlTableRendererBase exten
      */
      public void encodeInnerHtml(FacesContext facesContext, UIComponent component)throws IOException
      {
-
         UIData uiData = (UIData) component;
         ResponseWriter writer = facesContext.getResponseWriter();
 
         int rowCount = uiData.getRowCount();
 
+        int newspaperColumns = getNewspaperColumns(component);
+
+        if (rowCount == -1 && newspaperColumns == 1)
+        {
+            encodeInnerHtmlUnknownRowCount(facesContext, component);
+            return;
+        }
+        
         if (rowCount == 0)
         {
             //nothing to render, to get valid xhtml we render an empty dummy row
@@ -377,7 +407,6 @@ public class HtmlTableRendererBase exten
            }
         }
 
-        int newspaperColumns = getNewspaperColumns(component);
         int newspaperRows;
         if((last - first) % newspaperColumns == 0)
         {
@@ -390,24 +419,7 @@ public class HtmlTableRendererBase exten
         boolean newspaperHorizontalOrientation = isNewspaperHorizontalOrientation(component);
         
         // get the row indizes for which a new TBODY element should be created
-        Integer[] bodyrows = null;
-        String bodyrowsAttr = (String) component.getAttributes().get(JSFAttr.BODYROWS_ATTR);
-        if(bodyrowsAttr != null && !"".equals(bodyrowsAttr)) 
-        {   
-            String[] bodyrowsString = StringUtils.trim(StringUtils.splitShortString(bodyrowsAttr, ','));
-            // parsing with no exception handling, because of JSF-spec: 
-            // "If present, this must be a comma separated list of integers."
-            bodyrows = new Integer[bodyrowsString.length];
-            for(int i = 0; i < bodyrowsString.length; i++) 
-            {
-                bodyrows[i] = new Integer(bodyrowsString[i]);
-            }
-            
-        }
-        else
-        {
-            bodyrows = ZERO_INT_ARRAY;
-        }
+        Integer[] bodyrows = getBodyRows(facesContext, component);
         int bodyrowsCount = 0;
 
         // walk through the newspaper rows
@@ -520,6 +532,113 @@ public class HtmlTableRendererBase exten
             writer.endElement(HTML.TBODY_ELEM);
         }
     }
+     
+    private void encodeInnerHtmlUnknownRowCount(FacesContext facesContext, UIComponent component)throws IOException
+    {
+        UIData uiData = (UIData) component;
+        ResponseWriter writer = facesContext.getResponseWriter();
+
+        Styles styles = getStyles(uiData);
+        
+        Integer[] bodyrows = getBodyRows(facesContext, component);
+        int bodyrowsCount = 0;
+        
+        int first = uiData.getFirst();
+        int rows = uiData.getRows();
+        int currentRow = first;
+        boolean isRowRendered = false;
+        
+        while(true)
+        {
+            uiData.setRowIndex(currentRow);
+            if (!uiData.isRowAvailable())
+            {
+                break;
+            }
+            
+            isRowRendered = true;
+            
+            // first column in table, start new row
+            beforeRow(facesContext, uiData);
+
+            // is the current row listed in the bodyrows attribute
+            if(ArrayUtils.contains(bodyrows, currentRow))  
+            {
+                // close any preopened TBODY element first
+                if(bodyrowsCount != 0) 
+                {
+                    HtmlRendererUtils.writePrettyLineSeparator(facesContext);
+                    writer.endElement(HTML.TBODY_ELEM);
+                }
+                HtmlRendererUtils.writePrettyLineSeparator(facesContext);
+                writer.startElement(HTML.TBODY_ELEM, uiData); 
+                // Do not attach bodyrowsCount to the first TBODY element, because of backward compatibility
+                writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext) + ":tbody_element" + 
+                    (bodyrowsCount == 0 ? "" : bodyrowsCount), null);
+                bodyrowsCount++;
+            }
+            
+            HtmlRendererUtils.writePrettyLineSeparator(facesContext);
+            renderRowStart(facesContext, writer, uiData, styles, currentRow);
+            
+            List<UIComponent> children = null;
+            for (int j = 0, size = getChildCount(component); j < size; j++)
+            {
+                if (children == null)
+                {
+                    children = getChildren(component);
+                }
+                UIComponent child = (UIComponent) children.get(j);
+                if (child.isRendered())
+                {
+                    boolean columnRendering = child instanceof UIColumn;
+                    
+                    if (columnRendering)
+                    {
+                        beforeColumn(facesContext, uiData, j);
+                    }
+                       
+                    encodeColumnChild(facesContext, writer, uiData, child, 
+                            styles, j);                    
+                   
+                    if (columnRendering)
+                    {
+                        afterColumn(facesContext, uiData, j);
+                    }
+                }
+            }
+
+            renderRowEnd(facesContext, writer, uiData);
+            afterRow(facesContext, uiData);
+            
+            currentRow++;
+
+            if (rows > 0 && currentRow-first > rows )
+            {
+                break;
+            }
+        }
+        
+        if (!isRowRendered)
+        {
+            //nothing to render, to get valid xhtml we render an empty dummy row
+            writer.startElement(HTML.TBODY_ELEM, uiData);
+            writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext) + ":tbody_element", null);
+            writer.startElement(HTML.TR_ELEM, uiData);
+            writer.startElement(HTML.TD_ELEM, uiData);
+            writer.endElement(HTML.TD_ELEM);
+            writer.endElement(HTML.TR_ELEM);
+            writer.endElement(HTML.TBODY_ELEM);
+            return;
+        }
+
+        if(bodyrowsCount != 0)
+        {
+            // close the last TBODY element
+            HtmlRendererUtils.writePrettyLineSeparator(facesContext);
+            writer.endElement(HTML.TBODY_ELEM);
+        }
+    }
 
     protected void encodeColumnChild(FacesContext facesContext, ResponseWriter writer,
         UIData uiData, UIComponent component, Styles styles, int columnStyleIndex) throws IOException