You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2007/02/14 20:07:35 UTC

svn commit: r507657 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/beaneditor/ main/java/org/apache/tapestry/corelib/components/ main/java/org/apache/tapestry/grid/ main/java/org/apache/tapestry/internal/beaneditor/ mai...

Author: hlship
Date: Wed Feb 14 11:07:34 2007
New Revision: 507657

URL: http://svn.apache.org/viewvc?view=rev&rev=507657
Log:
Add basic sorting support to the Grid component.
Add a sortable property to PropertyModel, which defaults to true when the propertyType is Comparable.
Change the Any component to only render an id attribute if its id parameter is bound (to a non-null value).

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridColumns.properties
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/sort-asc.png   (with props)
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/sort-desc.png   (with props)
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/grid/
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/grid/Datum.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/grid/ListGridDataSourceTest.java
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/beaneditor/PropertyModel.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Any.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Grid.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/grid/GridDataSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/beaneditor/PropertyModelImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/grid/ListGridDataSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/grid/NullDataSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/Grid.html
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridColumns.html
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridRows.html
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/default.css
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/AnyDemo.java

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/beaneditor/PropertyModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/beaneditor/PropertyModel.java?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/beaneditor/PropertyModel.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/beaneditor/PropertyModel.java Wed Feb 14 11:07:34 2007
@@ -77,4 +77,13 @@
 
     /** Returns the containing model, often used for "fluent" construction of the model. */
     BeanModel model();
+
+    /**
+     * Returns true if the property can be used for sorting. By default, this is true only if the
+     * property type implements Comparable.
+     */
+    boolean isSortable();
+
+    /** Updates sortable and returns the model for further changes. */
+    PropertyModel sortable(boolean sortable);
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java Wed Feb 14 11:07:34 2007
@@ -53,9 +53,19 @@
     @Environmental
     private PageRenderSupport _support;
 
+    /**
+     * If true, then then no link element is rendered (and no informal parameters as well). The body
+     * is, however, still rendered.
+     */
+    @Parameter
+    private boolean _disabled;
+
     @BeginRender
     void begin(MarkupWriter writer)
     {
+        if (_disabled)
+            return;
+
         String clientId = _support.allocateClientId(_resources.getId());
 
         Object[] contextArray = _context == null ? new Object[0] : _context.toArray();
@@ -70,6 +80,9 @@
     @AfterRender
     void end(MarkupWriter writer)
     {
+        if (_disabled)
+            return;
+
         writer.end(); // <a>
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Any.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Any.java?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Any.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Any.java Wed Feb 14 11:07:34 2007
@@ -39,6 +39,14 @@
     @Parameter(value = "prop:componentResources.elementName", defaultPrefix = "literal")
     private String _element;
 
+    /**
+     * The base value for the id attribute. If non-null, then a <em>unique</em> value is obtained,
+     * and the <code>id</code> attribute is added to the element. The actual unique id is
+     * available via the {@link #getClientId() clientId property}.
+     */
+    @Parameter(defaultPrefix = "literal")
+    private String _id;
+
     @Inject
     private ComponentResources _resources;
 
@@ -47,22 +55,32 @@
 
     private String _clientId;
 
+    /**
+     * Starts the element, and renders the id attribute (if the id parameter is non-null).
+     */
     void beginRender(MarkupWriter writer)
     {
-        String componentId = _resources.getId();
-
-        _clientId = _pageRenderSupport.allocateClientId(componentId);
+        writer.element(_element);
 
-        writer.element(_element, "id", _clientId);
+        if (_id != null)
+        {
+            _clientId = _pageRenderSupport.allocateClientId(_id);
+            writer.attributes("id", _clientId);
+        }
 
         _resources.renderInformalParameters(writer);
     }
 
+    /** Ends the element. */
     void afterRender(MarkupWriter writer)
     {
         writer.end();
     }
 
+    /**
+     * The page-unique id, rendered out as the <code>id</code> attribute of the tag. This will be
+     * null if the component's id parameter is unbound or otherwise null.
+     */
     public String getClientId()
     {
         return _clientId;

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Grid.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Grid.java?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Grid.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Grid.java Wed Feb 14 11:07:34 2007
@@ -23,6 +23,7 @@
 import org.apache.tapestry.annotations.Persist;
 import org.apache.tapestry.annotations.SupportsInformalParameters;
 import org.apache.tapestry.beaneditor.BeanModel;
+import org.apache.tapestry.beaneditor.PropertyModel;
 import org.apache.tapestry.grid.GridDataSource;
 import org.apache.tapestry.grid.GridModelProvider;
 import org.apache.tapestry.internal.bindings.AbstractBinding;
@@ -46,6 +47,12 @@
     @Persist
     private int _currentPage = 1;
 
+    @Persist
+    private String _sortColumnId;
+
+    @Persist
+    private boolean _sortAscending = true;
+
     @Parameter
     private Object _row;
 
@@ -73,6 +80,11 @@
 
     @SuppressWarnings("unused")
     @Component(parameters =
+    { "sortColumnId=sortColumnId", "sortAscending=sortAscending" })
+    private GridColumns _columns;
+
+    @SuppressWarnings("unused")
+    @Component(parameters =
     { "rowClass=rowClass", "provider=this", "rowsPerPage=rowsPerPage", "currentPage=currentPage",
             "row=row" })
     private GridRows _rows;
@@ -123,9 +135,32 @@
 
         // If there's no rows, display the empty block placeholder.
 
-        if (_dataSource.getAvailableRows() == 0)
+        int availableRows = _dataSource.getAvailableRows();
+
+        if (availableRows == 0)
             return _empty;
 
+        PropertyModel sortModel = null;
+
+        if (_sortColumnId != null)
+        {
+            for (String name : _model.getPropertyNames())
+            {
+                PropertyModel propertyModel = _model.get(name);
+
+                if (propertyModel.getId().equals(_sortColumnId))
+                {
+                    sortModel = propertyModel;
+                    break;
+                }
+            }
+        }
+
+        int startIndex = (_currentPage - 1) * _rowsPerPage;
+        int endIndex = Math.min(startIndex + _rowsPerPage - 1, availableRows - 1);
+
+        _dataSource.prepare(startIndex, endIndex, sortModel, _sortAscending);
+
         return null;
     }
 
@@ -183,6 +218,26 @@
     public void setRowsPerPage(int rowsPerPage)
     {
         _rowsPerPage = rowsPerPage;
+    }
+
+    public boolean isSortAscending()
+    {
+        return _sortAscending;
+    }
+
+    public String getSortColumnId()
+    {
+        return _sortColumnId;
+    }
+
+    public void setSortAscending(boolean sortAscending)
+    {
+        _sortAscending = sortAscending;
+    }
+
+    public void setSortColumnId(String sortColumnId)
+    {
+        _sortColumnId = sortColumnId;
     }
 
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java Wed Feb 14 11:07:34 2007
@@ -16,9 +16,14 @@
 
 import java.util.List;
 
+import org.apache.tapestry.Asset;
+import org.apache.tapestry.annotations.Component;
+import org.apache.tapestry.annotations.Inject;
+import org.apache.tapestry.annotations.OnEvent;
 import org.apache.tapestry.annotations.Parameter;
 import org.apache.tapestry.beaneditor.PropertyModel;
 import org.apache.tapestry.grid.GridModelProvider;
+import org.apache.tapestry.ioc.Messages;
 
 /**
  * Renders out the column headers for the grid. Eventually, this will include control over column
@@ -31,6 +36,71 @@
 
     private PropertyModel _columnModel;
 
+    @Parameter(required = true)
+    private String _sortColumnId;
+
+    @Parameter(required = true)
+    private boolean _sortAscending;
+
+    @SuppressWarnings("unused")
+    @Component(parameters =
+    { "disabled=sortDisabled", "context=columnModel.id", "class=sortLinkClass" })
+    private ActionLink _sort, _sort2;
+
+    @Inject("sort-asc.png")
+    private Asset _ascendingAsset;
+
+    @Inject("sort-desc.png")
+    private Asset _descendingAsset;
+    
+    @Inject
+    private Messages _messages;
+
+    public boolean isSortDisabled()
+    {
+        return !_columnModel.isSortable();
+    }
+
+    public String getSortLinkClass()
+    {
+        if (isActiveSortColumn())
+            return _sortAscending ? "t-sort-column-ascending" : "t-sort-column-descending";
+
+        return null;
+    }
+
+    public boolean isActiveSortColumn()
+    {
+        return _columnModel.getId().equals(_sortColumnId);
+    }
+
+    @OnEvent(component =
+    { "sort", "sort2" })
+    void sort(String columnId)
+    {
+        if (columnId.equals(_sortColumnId))
+        {
+            _sortAscending = !_sortAscending;
+        }
+        else
+        {
+            _sortColumnId = columnId;
+            _sortAscending = true;
+        }
+    }
+    
+    public Asset getIcon()
+    {
+        return _sortAscending ? _ascendingAsset : _descendingAsset;
+    }
+
+    public String getIconLabel()
+    {
+        String key = _sortAscending ? "ascending" : "descending";
+        
+        return _messages.get(key);
+    }
+    
     public List<String> getColumnNames()
     {
         return _dataProvider.getDataModel().getPropertyNames();

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/grid/GridDataSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/grid/GridDataSource.java?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/grid/GridDataSource.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/grid/GridDataSource.java Wed Feb 14 11:07:34 2007
@@ -14,12 +14,37 @@
 
 package org.apache.tapestry.grid;
 
+import org.apache.tapestry.beaneditor.PropertyModel;
+import org.apache.tapestry.corelib.components.Grid;
+
+/**
+ * Defines how a {@link Grid} components (and its sub-components) gain access to the row data that
+ * is displayed on the page. In many cases, this is just a wrapper around a simple List, but the
+ * abstractions exist to support access to a large data set that is accessible in sections.
+ */
 public interface GridDataSource
 {
     /** Returns the number of rows available in the data source. */
     int getAvailableRows();
 
-    /** Returns the row value at the provided index. */
+    /**
+     * Invoked to allow the source to prepare to present values. This gives the source a chance to
+     * pre-fetch data (when appropriate) and informs the source of the desired sort order.
+     * 
+     * @param startIndex
+     *            the starting index to be retrieved
+     * @param endIndex
+     *            the ending index to be retrieved
+     * @param sortModel
+     *            the property model that defines what data will be used for sorting, or null if no
+     *            sorting is required (in which case, whatever natural order is provided by the
+     *            underlying data source will be used)
+     * @param ascending
+     *            if true, then sort ascending, else decending
+     */
+    void prepare(int startIndex, int endIndex, PropertyModel sortModel, boolean ascending);
+
+    /** Returns the row value at the provided index. This method will be invoked in sequential order. */
     Object getRowValue(int index);
 
     /**

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/beaneditor/PropertyModelImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/beaneditor/PropertyModelImpl.java?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/beaneditor/PropertyModelImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/beaneditor/PropertyModelImpl.java Wed Feb 14 11:07:34 2007
@@ -21,6 +21,7 @@
 import org.apache.tapestry.beaneditor.PropertyModel;
 import org.apache.tapestry.internal.TapestryUtils;
 import org.apache.tapestry.ioc.Messages;
+import org.apache.tapestry.ioc.services.ClassFabUtils;
 
 public class PropertyModelImpl implements PropertyModel
 {
@@ -38,8 +39,10 @@
 
     private String _editorType;
 
-    public PropertyModelImpl(BeanModel model, final String name,
-            final PropertyConduit conduit, Messages messages)
+    private boolean _sortable;
+
+    public PropertyModelImpl(BeanModel model, final String name, final PropertyConduit conduit,
+            Messages messages)
     {
         _model = model;
         _name = name;
@@ -48,8 +51,14 @@
         _id = TapestryUtils.extractIdFromPropertyExpression(name);
         _order = TapestryUtils.defaultOrder(conduit);
 
-        
         _label = TapestryUtils.defaultLabel(_id, messages, name);
+
+        // Primitive types need to be converted to wrapper types before checking to see
+        // if they are sortable.
+        
+        Class wrapperType = ClassFabUtils.getWrapperType(conduit.getPropertyType());
+
+        _sortable = Comparable.class.isAssignableFrom(wrapperType);
     }
 
     public String getId()
@@ -113,5 +122,16 @@
     public String getEditorType()
     {
         return _editorType;
+    }
+
+    public boolean isSortable()
+    {
+        return _sortable;
+    }
+
+    public PropertyModel sortable(boolean sortable)
+    {
+        _sortable = sortable;
+        return this;
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/grid/ListGridDataSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/grid/ListGridDataSource.java?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/grid/ListGridDataSource.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/grid/ListGridDataSource.java Wed Feb 14 11:07:34 2007
@@ -14,26 +14,88 @@
 
 package org.apache.tapestry.internal.grid;
 
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
 import static org.apache.tapestry.ioc.internal.util.Defense.notNull;
 
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
+import org.apache.tapestry.PropertyConduit;
+import org.apache.tapestry.beaneditor.PropertyModel;
 import org.apache.tapestry.grid.GridDataSource;
 
 public class ListGridDataSource implements GridDataSource
 {
     private final List _list;
 
+    @SuppressWarnings("unchecked")
     public ListGridDataSource(final List list)
     {
         notNull(list, "list");
 
-        _list = list;
+        // Copy the list so that we can sort it without distubing the original
+
+        _list = newList(list);
     }
 
     public int getAvailableRows()
     {
         return _list.size();
+    }
+
+    @SuppressWarnings("unchecked")
+    public void prepare(int startIndex, int endIndex, PropertyModel sortModel,
+            final boolean ascending)
+    {
+        if (sortModel == null)
+            return;
+
+        final PropertyConduit conduit = sortModel.getConduit();
+
+        final Comparator valueComparator = new Comparator<Comparable>()
+        {
+            public int compare(Comparable o1, Comparable o2)
+            {
+                // Simplify comparison, and handle case where both are nulls.
+
+                if (o1 == o2)
+                    return 0;
+
+                if (o2 == null)
+                    return 1;
+
+                if (o1 == null)
+                    return -1;
+
+                return o1.compareTo(o2);
+            }
+        };
+
+        final Comparator rowComparator = new Comparator()
+        {
+            public int compare(Object row1, Object row2)
+            {
+                Comparable value1 = (Comparable) conduit.get(row1);
+                Comparable value2 = (Comparable) conduit.get(row2);
+
+                return valueComparator.compare(value1, value2);
+            }
+        };
+
+        final Comparator reverseComparator = new Comparator()
+        {
+            public int compare(Object o1, Object o2)
+            {
+                int modifier = ascending ? 1 : -1;
+
+                return modifier * rowComparator.compare(o1, o2);
+            }
+        };
+
+        // We can freely sort this list because its just a copy.
+
+        Collections.sort(_list, reverseComparator);
     }
 
     /** Returns the type of the first element in the list, or null if the list is empty. */

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/grid/NullDataSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/grid/NullDataSource.java?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/grid/NullDataSource.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/grid/NullDataSource.java Wed Feb 14 11:07:34 2007
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry.internal.grid;
 
+import org.apache.tapestry.beaneditor.PropertyModel;
 import org.apache.tapestry.grid.GridDataSource;
 
 /**
@@ -29,6 +30,10 @@
     public Class getRowType()
     {
         return null;
+    }
+
+    public void prepare(int startIndex, int endIndex, PropertyModel sortModel, boolean ascending)
+    {
     }
 
     public Object getRowValue(int index)

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java Wed Feb 14 11:07:34 2007
@@ -198,7 +198,6 @@
         try
         {
             boolean p = ctClass.stopPruning(true);
-            ctClass.writeFile();
             ctClass.writeFile(JAVASSIST_WRITE_DIR);
             ctClass.defrost();
             ctClass.stopPruning(p);

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/Grid.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/Grid.html?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/Grid.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/Grid.html Wed Feb 14 11:07:34 2007
@@ -1,6 +1,6 @@
 <div class="t-data-grid" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
 	<table class="t-data-grid" cellspacing="0">
-		<thead t:id="columns" t:type="GridColumns"/>
+		<thead t:id="columns"/>
 		<tbody>
 			<t:comp id="rows"/>
 		</tbody>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridColumns.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridColumns.html?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridColumns.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridColumns.html Wed Feb 14 11:07:34 2007
@@ -1,7 +1,12 @@
 <thead xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
     <tr>
         <th t:type="Loop" source="columnNames" value="columnName" volatile="true" class="prop:cellClass">
-           ${columnModel.label}
+           <a t:id="sort">${columnModel.label}</a>
+            <t:comp type="If" test="activeSortColumn">
+                <a t:id="sort2">
+                    <img t:type="Img" src="icon" alt="prop:iconLabel"/>
+                </a>
+            </t:comp>
         </th>
     </tr>
 </thead>

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridColumns.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridColumns.properties?view=auto&rev=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridColumns.properties (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridColumns.properties Wed Feb 14 11:07:34 2007
@@ -0,0 +1,16 @@
+# Copyright 2007 The Apache Software Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+ascending=[Asc]
+descending=[Desc]
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridRows.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridRows.html?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridRows.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/GridRows.html Wed Feb 14 11:07:34 2007
@@ -1,4 +1,4 @@
-<tr t:id="row" class="rowClass" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+<tr t:id="row" class="prop:rowClass" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
     <t:comp type="loop" source="propertyNames" value="propertyName" volatile="true">
         <td t:id="cell" class="prop:cellClass">
              <t:comp type="GridCell" model="columnModel" row="row" resources="componentResources.containerResources"/>

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/sort-asc.png
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/sort-asc.png?view=auto&rev=507657
==============================================================================
Binary file - no diff available.

Propchange: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/sort-asc.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/sort-desc.png
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/sort-desc.png?view=auto&rev=507657
==============================================================================
Binary file - no diff available.

Propchange: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/components/sort-desc.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/default.css
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/default.css?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/default.css (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/default.css Wed Feb 14 11:07:34 2007
@@ -166,6 +166,7 @@
 TABLE.t-data-grid THEAD TR TH
 {
   padding: 3px;
+  white-space: nowrap;
 }
 
 TABLE.t-data-grid
@@ -211,3 +212,13 @@
   background-color: black;
   border: 1px solid black;
 }
+
+TABLE.t-data-grid TR TH A
+{
+  color: white;
+}
+
+IMG
+{
+  border: none;
+}
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java Wed Feb 14 11:07:34 2007
@@ -64,9 +64,9 @@
         clickAndWait("link=AnyDemo");
 
         assertSourcePresent(
-                "<span class=\"title\" id=\"title\">Page Title</span>",
-                "<div class=\"heading\" id=\"heading\">Heading</div>",
-                "<h2 class=\"section\" id=\"section\">Section</h2>",
+                "<span class=\"title\">Page Title</span>",
+                "<div class=\"heading\">Heading</div>",
+                "<h2 class=\"section\">Section</h2>",
                 "<li id=\"item\">Item (item)</li>",
                 "<li id=\"item_0\">Item (item_0)</li>",
                 "<li id=\"item_1\">Item (item_1)</li>");
@@ -368,7 +368,7 @@
         // the optional component from inside the NeverRender, resurrected to render on the page
         // after all.
 
-        assertText("//span[@id='optional']", "Optional Text");
+        assertText("//span[@id='container']/span", "Optional Text");
 
         assertTextPresent("Should now show up:");
     }
@@ -770,7 +770,7 @@
     }
 
     /**
-     * Basic Grid rendering, with a column render override.
+     * Basic Grid rendering, with a column render override. Also tests sorting.
      */
     @Test
     public void basic_grid()
@@ -820,6 +820,27 @@
         clickAndWait("link=69");
 
         assertText("//tr[22]/td[1]", "radioioAmbient");
+
+        // Sort ascending (and we're on the last page, with the highest ratings).
+
+        clickAndWait("link=Rating");
+
+        assertTextSeries(
+                "//tr[22]/td[%d]",
+                1,
+                "Mona Lisa Overdrive",
+                "Labyrinth",
+                "Juno Reactor",
+                "Dance",
+                "31",
+                "*****");
+
+        // Toggle to sort descending
+
+        clickAndWait("link=Rating");
+
+        assertTextSeries("//tr[1]/td[%d]", 1, "Hey Blondie", "Out from Out Where");
+
     }
 
     @Test

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/AnyDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/AnyDemo.java?view=diff&rev=507657&r1=507656&r2=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/AnyDemo.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/AnyDemo.java Wed Feb 14 11:07:34 2007
@@ -19,7 +19,7 @@
 
 public class AnyDemo
 {
-    @Component
+    @Component(parameters = "id=item")
     private Any _item;
 
     public Any getItem()

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/grid/Datum.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/grid/Datum.java?view=auto&rev=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/grid/Datum.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/grid/Datum.java Wed Feb 14 11:07:34 2007
@@ -0,0 +1,38 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.internal.grid;
+
+public class Datum
+{
+    private final int _id;
+
+    private final String _value;
+
+    public Datum(final int id, final String value)
+    {
+        _id = id;
+        _value = value;
+    }
+
+    public int getId()
+    {
+        return _id;
+    }
+
+    public String getValue()
+    {
+        return _value;
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/grid/ListGridDataSourceTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/grid/ListGridDataSourceTest.java?view=auto&rev=507657
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/grid/ListGridDataSourceTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/grid/ListGridDataSourceTest.java Wed Feb 14 11:07:34 2007
@@ -0,0 +1,122 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.internal.grid;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.beaneditor.BeanModel;
+import org.apache.tapestry.beaneditor.PropertyModel;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.ioc.Messages;
+import org.apache.tapestry.services.BeanModelSource;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class ListGridDataSourceTest extends InternalBaseTestCase
+{
+    // Just arbitrary numbers ...
+
+    private static final int FRED = 99;
+
+    private static final int BARNEY = 23;
+
+    private static final int WILMA = 107;
+
+    private static final int BETTY = 298;
+
+    // Arrays.asList returns an unmodifiable list
+
+    private final List _raw = Arrays.asList(
+            new Datum(FRED, "Fred"),
+            new Datum(BARNEY, "Barney"),
+            new Datum(WILMA, null),
+            new Datum(BETTY, null));
+
+    private final ListGridDataSource _source = new ListGridDataSource(_raw);
+
+    private BeanModel _model;
+
+    @BeforeClass
+    public void setup()
+    {
+        BeanModelSource source = getService(BeanModelSource.class);
+
+        ComponentResources resources = newComponentResources();
+        Messages messages = newMessages();
+
+        train_getMessages(resources, messages);
+        stub_contains(messages, false);
+
+        replay();
+
+        _model = source.create(Datum.class, false, resources);
+
+        verify();
+    }
+
+    @AfterClass
+    public void cleanup()
+    {
+        _model = null;
+    }
+
+    @Test
+    public void sort_on_number_ascending()
+    {
+        sort("id", true, BARNEY, FRED, WILMA, BETTY);
+    }
+
+    @Test
+    public void sort_on_number_descending()
+    {
+        sort("id", false, BETTY, WILMA, FRED, BARNEY);
+    }
+
+    @Test
+    public void sort_on_string_value_ascending()
+    {
+        // Nulls sort first
+
+        // Without a secondary sort column, it's kind of arbitrary whether WILMA or BETTY is sorted
+        // first.
+
+        sort("value", true, WILMA, BETTY, BARNEY, FRED);
+    }
+
+    @Test
+    public void sort_on_string_value_descending()
+    {
+        sort("value", false, FRED, BARNEY, WILMA, BETTY);
+    }
+
+    private void sort(String propertyName, boolean ascending, int... ids)
+    {
+        PropertyModel propertyModel = _model.get(propertyName);
+
+        int availableRows = _source.getAvailableRows();
+
+        _source.prepare(0, availableRows - 1, propertyModel, ascending);
+
+        for (int i = 0; i < ids.length; i++)
+        {
+            Datum row = (Datum) _source.getRowValue(i);
+
+            assertEquals(row.getId(), ids[i], "Id for Datum #" + i);
+        }
+    }
+}