Author: hlship
Date: Tue Feb 26 11:21:44 2008
New Revision: 631344

URL: http://svn.apache.org/viewvc?rev=631344&view=rev
Log:
TAPESTRY-2188: GridModel and GridDataSource should be changed to support 
multiple sort columns

Added:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/ColumnSort.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridSortModel.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/SortConstraint.java
Modified:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/beaneditor/BeanModel.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Grid.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridRows.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridDataSource.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridModel.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanEditorMessages.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanModelImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/grid/CollectionGridDataSource.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/grid/NullDataSource.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/PropertyConduitSource.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/beaneditor/BeanEditorStrings.properties
    tapestry/tapestry5/trunk/tapestry-core/src/site/apt/upgrade.apt
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/GridDemo.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/grid/CollectionGridDataSourceTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/BeanModelSourceImplTest.java

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/beaneditor/BeanModel.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/beaneditor/BeanModel.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/beaneditor/BeanModel.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/beaneditor/BeanModel.java
 Tue Feb 26 11:21:44 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -15,17 +15,20 @@
 package org.apache.tapestry.beaneditor;
 
 import org.apache.tapestry.PropertyConduit;
-import org.apache.tapestry.services.BeanModelSource;
 
 import java.util.List;
 
 /**
- * Provides the information necessary to build a user interface to view, 
create or edit an instance
- * of a particular type.
+ * Provides the information necessary to build a user interface to view, 
create or edit an instance of a particular
+ * type.
  * <p/>
  * BeanModels are not thread-safe, they are also not serializable.
+ * <p>
+ * Here, and in [EMAIL PROTECTED] 
org.apache.tapestry.beaneditor.PropertyModel}, the term "propertyName" is used 
for simplicitly.
+ * However, a full [EMAIL PROTECTED] 
org.apache.tapestry.services.PropertyConduitSource#create(Class, String) 
property expression}
+ * may be utilized when [EMAIL PROTECTED] #add(String) adding new properties 
to an existing BeanModel}. 
  *
- * @see BeanModelSource
+ * @see org.apache.tapestry.services.BeanModelSource
  */
 public interface BeanModel
 {
@@ -49,8 +52,16 @@
     PropertyModel get(String propertyName);
 
     /**
-     * Adds a new property to the model, returning its mutable model for 
further refinement. The
-     * property is added to the <em>end</em> of the list of properties.
+     * Returns the identified model.  Property ids are a stripped version of 
the property name. Case is ignored.
+     *
+     * @param propertyId matched caselessly against [EMAIL PROTECTED] 
org.apache.tapestry.beaneditor.PropertyModel#getId()}
+     * @throws RuntimeException if the bean editor model does not have a 
property model with the indicated id
+     */
+    PropertyModel getById(String propertyId);
+
+    /**
+     * Adds a new property to the model, returning its mutable model for 
further refinement. The property is added to
+     * the <em>end</em> of the list of properties.
      *
      * @param propertyName name of property to add
      * @return the new property model (for further configuration)
@@ -65,8 +76,7 @@
      * @param existingPropertyName the name of an existing property (this must 
exist)
      * @param propertyName         the new property to add
      * @return the new property model (for further configuration)
-     * @throws RuntimeException if the existing property does not exist, or if 
the new property already does
-     *                          exist
+     * @throws RuntimeException if the existing property does not exist, or if 
the new property already does exist
      */
     PropertyModel add(RelativePosition position, String existingPropertyName, 
String propertyName);
 
@@ -79,8 +89,7 @@
      * @param conduit              conduit used to read or update the 
property; this may be null for a synthetic or
      *                             placeholder property
      * @return the new property model (for further configuration)
-     * @throws RuntimeException if the existing property does not exist, or if 
the new property already does
-     *                          exist
+     * @throws RuntimeException if the existing property does not exist, or if 
the new property already does exist
      */
     PropertyModel add(RelativePosition position, String existingPropertyName, 
String propertyName,
                       PropertyConduit conduit);
@@ -89,16 +98,16 @@
      * Adds a new property to the model, returning its mutable model for 
further refinement.
      *
      * @param propertyName name of property to add
-     * @param conduit      the conduit used to read or update the property; 
this may be null for a synthetic
-     *                     or placeholder property
+     * @param conduit      the conduit used to read or update the property; 
this may be null for a synthetic or
+     *                     placeholder property
      * @return the model for the property
      * @throws RuntimeException if the property already exists
      */
     PropertyModel add(String propertyName, PropertyConduit conduit);
 
     /**
-     * Removes the named properties from the model, if present. It is not 
considered an error to
-     * remove a property that does not exist.
+     * Removes the named properties from the model, if present. It is not 
considered an error to remove a property that
+     * does not exist.
      *
      * @param propertyName the names of properties to be removed (case 
insensitive)
      * @return the model for further modifications
@@ -106,8 +115,8 @@
     BeanModel remove(String... propertyName);
 
     /**
-     * Re-orders the properties of the model into the specified order. 
Existing properties that are
-     * not indicated are retained, but ordered to the end of the list.
+     * Re-orders the properties of the model into the specified order. 
Existing properties that are not indicated are
+     * retained, but ordered to the end of the list.
      *
      * @param propertyName property names in order they should be displayed 
(case insensitive)
      * @return the model for further modifications

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Grid.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Grid.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Grid.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Grid.java
 Tue Feb 26 11:21:44 2008
@@ -22,23 +22,27 @@
 import org.apache.tapestry.beaneditor.BeanModel;
 import org.apache.tapestry.beaneditor.PropertyModel;
 import org.apache.tapestry.corelib.data.GridPagerPosition;
-import org.apache.tapestry.grid.GridDataSource;
-import org.apache.tapestry.grid.GridModel;
+import org.apache.tapestry.grid.*;
+import org.apache.tapestry.internal.TapestryInternalUtils;
 import org.apache.tapestry.internal.beaneditor.BeanModelUtils;
 import org.apache.tapestry.internal.bindings.AbstractBinding;
 import org.apache.tapestry.ioc.annotations.Inject;
+import org.apache.tapestry.ioc.internal.util.Defense;
 import org.apache.tapestry.services.BeanModelSource;
 import org.apache.tapestry.services.FormSupport;
 
+import java.util.Collections;
+import java.util.List;
+
 /**
  * A grid presents tabular data. It is a composite component, created in terms 
of several sub-components. The
  * sub-components are statically wired to the Grid, as it provides access to 
the data and other models that they need.
  * <p/>
  * A Grid may operate inside a [EMAIL PROTECTED] 
org.apache.tapestry.corelib.components.Form}. By overriding the cell renderers 
of
- * properties, the default output-only
- * behavior can be changed to produce a complex form with individual control 
for editing properties of each row. This is
- * currently workable but less than ideal -- if the order of rows provided by 
the [EMAIL PROTECTED] GridDataSource} changes between
- * render and form submission, then there's the possibility that data will be 
applied to the wrong server-side objects.
+ * properties, the default output-only behavior can be changed to produce a 
complex form with individual control for
+ * editing properties of each row. This is currently workable but less than 
ideal -- if the order of rows provided by
+ * the [EMAIL PROTECTED] GridDataSource} changes between render and form 
submission, then there's the possibility that data will be
+ * applied to the wrong server-side objects.
  *
  * @see org.apache.tapestry.beaneditor.BeanModel
  * @see org.apache.tapestry.services.BeanModelSource
@@ -88,6 +92,15 @@
     private BeanModel _model;
 
     /**
+     * The model used to handle sorting of the Grid. This is generally not 
specified, and the built-in
+     * model supports only single column sorting. The sort constraints (the 
column that is sorted,
+     * and ascending vs. descending) is stored as persistent fields of the 
Grid component.
+     */
+    @Parameter
+    private GridSortModel _sortModel;
+
+
+    /**
      * A comma-separated list of property names to be removed from the [EMAIL 
PROTECTED] BeanModel}. The names are
      * case-insensitive.
      */
@@ -153,15 +166,15 @@
 
     @SuppressWarnings("unused")
     @Component(
-            parameters = {"lean=inherit:lean", "overrides=componentResources"})
+            parameters = { "lean=inherit:lean", "overrides=componentResources" 
})
     private GridColumns _columns;
 
     @SuppressWarnings("unused")
     @Component(
-            parameters = {"rowClass=rowClass", "rowsPerPage=rowsPerPage", 
"currentPage=currentPage", "row=row", "volatile=inherit:volatile", 
"lean=inherit:lean"})
+            parameters = { "rowClass=rowClass", "rowsPerPage=rowsPerPage", 
"currentPage=currentPage", "row=row", "volatile=inherit:volatile", 
"lean=inherit:lean" })
     private GridRows _rows;
 
-    @Component(parameters = {"source=dataSource", "rowsPerPage=rowsPerPage", 
"currentPage=currentPage"})
+    @Component(parameters = { "source=dataSource", "rowsPerPage=rowsPerPage", 
"currentPage=currentPage" })
     private GridPager _pager;
 
     @SuppressWarnings("unused")
@@ -176,6 +189,63 @@
     @Environmental(false)
     private FormSupport _formSupport;
 
+    /**
+     * Default implementation only allows a single column to be the sort 
column, and stores the sort information as
+     * persistent fields of the Grid component.
+     */
+    class DefaultGridSortModel implements GridSortModel
+    {
+        public ColumnSort getColumnSort(String columnId)
+        {
+            if (!TapestryInternalUtils.isEqual(columnId, _sortColumnId))
+                return ColumnSort.UNSORTED;
+
+            return getColumnSort();
+        }
+
+        private ColumnSort getColumnSort()
+        {
+            return _sortAscending ? ColumnSort.ASCENDING : 
ColumnSort.DESCENDING;
+        }
+
+
+        public void updateSort(String columnId)
+        {
+            Defense.notBlank(columnId, "columnId");
+
+            if (columnId.equals(_sortColumnId))
+            {
+                _sortAscending = !_sortAscending;
+                return;
+            }
+
+            _sortColumnId = columnId;
+            _sortAscending = true;
+        }
+
+        public List<SortConstraint> getSortContraints()
+        {
+            if (_sortColumnId == null)
+                return Collections.emptyList();
+
+            PropertyModel sortModel = _model.getById(_sortColumnId);
+
+            SortConstraint constraint = new SortConstraint(sortModel, 
getColumnSort());
+
+            return Collections.singletonList(constraint);
+        }
+
+        public void clear()
+        {
+            _sortColumnId = null;
+        }
+    }
+
+    GridSortModel defaultSortModel()
+    {
+        return new DefaultGridSortModel();
+    }
+
     Binding defaultModel()
     {
         final ComponentResources containerResources = 
_resources.getContainerResources();
@@ -242,23 +312,6 @@
 
         if (availableRows == 0) return;
 
-        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 maxPage = ((availableRows - 1) / _rowsPerPage) + 1;
 
         // This captures when the number of rows has decreased, typically due 
to deletions.
@@ -270,7 +323,7 @@
 
         int endIndex = Math.min(startIndex + _rowsPerPage - 1, availableRows - 
1);
 
-        _source.prepare(startIndex, endIndex, sortModel, _sortAscending);
+        _source.prepare(startIndex, endIndex, _sortModel.getSortContraints());
 
     }
 
@@ -294,6 +347,11 @@
         return _source;
     }
 
+    public GridSortModel getSortModel()
+    {
+        return _sortModel;
+    }
+
     public String getRowClass()
     {
         return _rowClass;
@@ -310,8 +368,8 @@
     }
 
     /**
-     * Returns the current row being rendered by the Grid. This property can 
be accessed
-     * as an alternative to binding the row parameter.
+     * Returns the current row being rendered by the Grid. This property can 
be accessed as an alternative to binding
+     * the row parameter.
      */
     public Object getRow()
     {
@@ -363,16 +421,5 @@
         return _pagerPosition.isMatchBottom() ? _pager : null;
     }
 
-    public void updateSort(String columnId)
-    {
-        if (columnId.equals(_sortColumnId))
-        {
-            _sortAscending = !_sortAscending;
-            return;
-        }
-
-        _sortColumnId = columnId;
-        _sortAscending = true;
 
-    }
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java
 Tue Feb 26 11:21:44 2008
@@ -22,8 +22,10 @@
 import org.apache.tapestry.annotations.Path;
 import org.apache.tapestry.annotations.SupportsInformalParameters;
 import org.apache.tapestry.beaneditor.PropertyModel;
+import org.apache.tapestry.grid.ColumnSort;
 import org.apache.tapestry.grid.GridConstants;
 import org.apache.tapestry.grid.GridModel;
+import org.apache.tapestry.grid.GridSortModel;
 import org.apache.tapestry.internal.TapestryInternalUtils;
 import org.apache.tapestry.ioc.Messages;
 import org.apache.tapestry.ioc.annotations.Inject;
@@ -52,15 +54,15 @@
     private boolean _lean;
 
     /**
-     * Where to look for informal parameter Blocks used to override column 
headers.  The default is to look for such overrides
-     * in the GridColumns component itself, but this is usually overridden.
+     * Where to look for informal parameter Blocks used to override column 
headers.  The default is to look for such
+     * overrides in the GridColumns component itself, but this is usually 
overridden.
      */
     @Parameter("componentResources")
     private ComponentResources _overrides;
 
 
     @SuppressWarnings("unused")
-    @Component(parameters = {"event=sort", "disabled=sortDisabled", 
"context=columnModel.id", "class=sortLinkClass"})
+    @Component(parameters = { "event=sort", "disabled=sortDisabled", 
"context=columnModel.id", "class=sortLinkClass" })
     private EventLink _sort, _sort2;
 
     @Inject
@@ -99,10 +101,26 @@
 
     public String getSortLinkClass()
     {
-        if (isActiveSortColumn())
-            return _gridModel.isSortAscending() ? 
GridConstants.SORT_ASCENDING_CLASS : GridConstants.SORT_DESCENDING_CLASS;
+        switch (getSortForColumn())
+        {
+            case ASCENDING:
+                return GridConstants.SORT_ASCENDING_CLASS;
 
-        return null;
+            case DESCENDING:
+                return GridConstants.SORT_DESCENDING_CLASS;
+
+            default:
+                return null;
+        }
+    }
+
+    private ColumnSort getSortForColumn()
+    {
+        GridSortModel sortModel = _gridModel.getSortModel();
+
+        String columnId = _columnModel.getId();
+
+        return sortModel.getColumnSort(columnId);
     }
 
     public String getHeaderClass()
@@ -124,26 +142,40 @@
 
     public boolean isActiveSortColumn()
     {
-        return _columnModel.getId().equals(_gridModel.getSortColumnId());
+        return getSortForColumn() != ColumnSort.UNSORTED;
     }
 
     void onSort(String columnId)
     {
-        _gridModel.updateSort(columnId);
+        _gridModel.getSortModel().updateSort(columnId);
     }
 
     public Asset getIcon()
     {
-        if (isActiveSortColumn()) return _gridModel.isSortAscending() ? 
_ascendingAsset : _descendingAsset;
-
-        return _sortableAsset;
+        switch (getSortForColumn())
+        {
+            case ASCENDING:
+                return _ascendingAsset;
+
+            case DESCENDING:
+                return _descendingAsset;
+
+            default:
+                return _sortableAsset;
+        }
     }
 
     public String getIconLabel()
     {
-        String key = isActiveSortColumn() ? (_gridModel.isSortAscending() ? 
"ascending" : "descending") : "sortable";
-
-        return _messages.get(key);
+        switch (getSortForColumn())
+        {
+            case ASCENDING:
+                return _messages.get("ascending");
+            case DESCENDING:
+                return _messages.get("descending");
+            default:
+                return _messages.get("sortable");
+        }
     }
 
     public List<String> getColumnNames()

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridRows.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridRows.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridRows.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridRows.java
 Tue Feb 26 11:21:44 2008
@@ -138,19 +138,26 @@
     {
         List<String> classes = CollectionFactory.newList();
 
+        String id = _gridModel.getDataModel().get(_propertyName).getId();
+
         if (!_lean)
         {
-            String id = _gridModel.getDataModel().get(_propertyName).getId();
-
             classes.add(id);
-        }
 
-        if (_columnModel.getId().equals(_gridModel.getSortColumnId()))
-        {
-            String sortClassName = _gridModel.isSortAscending() ? 
GridConstants.SORT_ASCENDING_CLASS : GridConstants.SORT_DESCENDING_CLASS;
+            switch (_gridModel.getSortModel().getColumnSort(id))
+            {
+                case ASCENDING:
+                    classes.add(GridConstants.SORT_ASCENDING_CLASS);
+                    break;
 
-            classes.add(sortClassName);
+                case DESCENDING:
+                    classes.add(GridConstants.SORT_DESCENDING_CLASS);
+                    break;
+                
+                default:
+            }
         }
+
 
         return TapestryInternalUtils.toClassAttributeValue(classes);
     }

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/ColumnSort.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/ColumnSort.java?rev=631344&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/ColumnSort.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/ColumnSort.java
 Tue Feb 26 11:21:44 2008
@@ -0,0 +1,22 @@
+package org.apache.tapestry.grid;
+
+/**
+ * Identifies how a column within a [EMAIL PROTECTED] 
org.apache.tapestry.grid.GridSortModel} is sorted.
+ */
+public enum ColumnSort
+{
+    /**
+     * A sort column and sorted in ascending order.
+     */
+    ASCENDING,
+
+    /**
+     * A sort column, and sorted in descending order.
+     */
+    DESCENDING,
+
+    /**
+     * Not a sort column.
+     */
+    UNSORTED
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridDataSource.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridDataSource.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridDataSource.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridDataSource.java
 Tue Feb 26 11:21:44 2008
@@ -14,13 +14,11 @@
 
 package org.apache.tapestry.grid;
 
-import org.apache.tapestry.beaneditor.BeanModel;
-import org.apache.tapestry.beaneditor.PropertyModel;
-import org.apache.tapestry.corelib.components.Grid;
+import java.util.List;
 
 /**
- * Defines how a [EMAIL PROTECTED] Grid} component (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
+ * Defines how a [EMAIL PROTECTED] 
org.apache.tapestry.corelib.components.Grid} component (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
@@ -31,17 +29,14 @@
     int getAvailableRows();
 
     /**
-     * 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.
+     * 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.  Sorting 
comes first, then extraction by range.
      *
-     * @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 descending
+     * @param startIndex      the starting index to be retrieved
+     * @param endIndex        the ending index to be retrieved
+     * @param sortConstraints identify how data is to be sorted
      */
-    void prepare(int startIndex, int endIndex, PropertyModel sortModel, 
boolean ascending);
+    void prepare(int startIndex, int endIndex, List<SortConstraint> 
sortConstraints);
 
     /**
      * Returns the row value at the provided index. This method will be 
invoked in sequential order.
@@ -49,8 +44,8 @@
     Object getRowValue(int index);
 
     /**
-     * Returns the type of value in the rows, or null if not known. This value 
is used to create a
-     * default [EMAIL PROTECTED] BeanModel} when no such model is explicitly 
provided.
+     * Returns the type of value in the rows, or null if not known. This value 
is used to create a default [EMAIL PROTECTED]
+     * org.apache.tapestry.beaneditor.BeanModel} when no such model is 
explicitly provided.
      *
      * @return the row type, or null
      */

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridModel.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridModel.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridModel.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridModel.java
 Tue Feb 26 11:21:44 2008
@@ -15,18 +15,18 @@
 package org.apache.tapestry.grid;
 
 import org.apache.tapestry.beaneditor.BeanModel;
-import org.apache.tapestry.corelib.components.Grid;
 
 /**
- * A provider of model data to the sub-components of the [EMAIL PROTECTED] 
Grid} component. The primary
- * implementor of this component is the Grid component itself.   In addition, 
provides access
- * to properties used to control paging and sort order.
+ * A provider of model data to the sub-components of the [EMAIL PROTECTED] 
org.apache.tapestry.corelib.components.Grid} component.
+ * The primary implementor of this component is the Grid component itself. 
This is effectively a way to package three
+ * values as a single parameter to components such as [EMAIL PROTECTED] 
org.apache.tapestry.corelib.components.GridColumns} and
+ * [EMAIL PROTECTED] org.apache.tapestry.corelib.components.GridRows}.
  */
 public interface GridModel
 {
     /**
-     * Returns the data model, which defines the columns (in terms of 
properties of the row type),
-     * and provides access to actual values for a given row instance.
+     * Returns the data model, which defines the columns (in terms of 
properties of the row type), and provides access
+     * to actual values for a given row instance.
      */
     BeanModel getDataModel();
 
@@ -36,25 +36,7 @@
     GridDataSource getDataSource();
 
     /**
-     * Indicates the current sort column.
-     *
-     * @return current sort column, or null for no column
+     * Returns the object used to track sorting behavior of the Grid.
      */
-    String getSortColumnId();
-
-    /**
-     * Indicates if soft is ascending or descending
-     *
-     * @return sort ascending flag
-     */
-    boolean isSortAscending();
-
-    /**
-     * Updates the column sort.  When the columnId matches the current sort 
column, the
-     * ascending/descending flag is toggled.  Otherwise, the specified column 
becomes
-     * the sort column, and sort mode is switched to ascending.
-     *
-     * @param columnId property id of column to sort on
-     */
-    void updateSort(String columnId);
+    GridSortModel getSortModel();
 }

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridSortModel.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridSortModel.java?rev=631344&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridSortModel.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridSortModel.java
 Tue Feb 26 11:21:44 2008
@@ -0,0 +1,49 @@
+// Copyright 2008 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.grid;
+
+import java.util.List;
+
+/**
+ * Models the sorting applied to the a [EMAIL PROTECTED] 
org.apache.tapestry.grid.GridDataSource}.
+ */
+public interface GridSortModel
+{
+    /**
+     * Identifies how (or if) a column is sorted.
+     *
+     * @param columnId
+     * @return the sort for the indicated column or [EMAIL PROTECTED] 
org.apache.tapestry.grid.ColumnSort#UNSORTED} if the column
+     *         is not used for sorting
+     */
+    ColumnSort getColumnSort(String columnId);
+
+    /**
+     * Updates the column sort.  The receiver determines how to handle the 
sort request.
+     *
+     * @param columnId property id of column to sort on
+     */
+    void updateSort(String columnId);
+
+    /**
+     * Returns a list of sort constraints, identifying which columns are 
sorted, and how.  May return an empty list (but
+     * won't return null).
+     *
+     * @see org.apache.tapestry.grid.GridDataSource#prepare(int, int, 
java.util.List)
+     */
+    List<SortConstraint> getSortContraints();
+
+    void clear();
+}

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/SortConstraint.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/SortConstraint.java?rev=631344&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/SortConstraint.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/SortConstraint.java
 Tue Feb 26 11:21:44 2008
@@ -0,0 +1,63 @@
+// Copyright 2008 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.grid;
+
+import org.apache.tapestry.beaneditor.PropertyModel;
+import org.apache.tapestry.ioc.internal.util.Defense;
+
+/**
+ * Identifies how a single column (identified as a [EMAIL PROTECTED] 
org.apache.tapestry.beaneditor.PropertyModel}) is sorted.
+ */
+public class SortConstraint
+{
+    private final PropertyModel _propertyModel;
+
+    private final ColumnSort _columnSort;
+
+    public SortConstraint(PropertyModel propertyModel, ColumnSort columnSort)
+    {
+        Defense.notNull(propertyModel, "propertyModel");
+        Defense.notNull(columnSort, "columnSort");
+
+        _propertyModel = propertyModel;
+        _columnSort = columnSort;
+    }
+
+    public PropertyModel getPropertyModel()
+    {
+        return _propertyModel;
+    }
+
+    public ColumnSort getColumnSort()
+    {
+        return _columnSort;
+    }
+
+    // equals() is useful for testing
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        SortConstraint that = (SortConstraint) o;
+
+        if (_columnSort != that._columnSort) return false;
+
+        return _propertyModel.equals(that._propertyModel);
+    }
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanEditorMessages.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanEditorMessages.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanEditorMessages.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanEditorMessages.java
 Tue Feb 26 11:21:44 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -34,5 +34,11 @@
     {
         return MESSAGES.format("unknown-property", beanType.getName(), 
propertyName, InternalUtils
                 .joinSorted(propertyNames));
+    }
+
+    static String unknownPropertyId(Class beanType, String propertyId, 
Collection<String> propertyIds)
+    {
+        return MESSAGES.format("unknown-property-id", beanType.getName(), 
propertyId,
+                               InternalUtils.joinSorted(propertyIds));
     }
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanModelImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanModelImpl.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanModelImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanModelImpl.java
 Tue Feb 26 11:21:44 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -130,9 +130,8 @@
 
     private CoercingPropertyConduitWrapper createConduit(String propertyName)
     {
-        return new 
CoercingPropertyConduitWrapper(_propertyConduitSource.create(
-                _beanType,
-                propertyName), _typeCoercer);
+        return new 
CoercingPropertyConduitWrapper(_propertyConduitSource.create(_beanType,
+                                                                               
 propertyName), _typeCoercer);
     }
 
     public PropertyModel get(String propertyName)
@@ -140,12 +139,33 @@
         PropertyModel propertyModel = _properties.get(propertyName);
 
         if (propertyModel == null)
-            throw new RuntimeException(BeanEditorMessages.unknownProperty(
-                    _beanType,
-                    propertyName,
-                    _properties.keySet()));
+            throw new 
RuntimeException(BeanEditorMessages.unknownProperty(_beanType,
+                                                                          
propertyName,
+                                                                          
_properties.keySet()));
 
         return propertyModel;
+    }
+
+    public PropertyModel getById(String propertyId)
+    {
+        for (PropertyModel model : _properties.values())
+        {
+            if (model.getId().equalsIgnoreCase(propertyId)) return model;
+        }
+
+        // Not found, so we throw an exception. A bit of work to set
+        // up the exception however.
+
+        List<String> ids = CollectionFactory.newList();
+
+        for (PropertyModel model : _properties.values())
+        {
+            ids.add(model.getId());
+        }
+
+        throw new 
RuntimeException(BeanEditorMessages.unknownPropertyId(_beanType,
+                                                                        
propertyId, ids));
+
     }
 
     public List<String> getPropertyNames()

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/grid/CollectionGridDataSource.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/grid/CollectionGridDataSource.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/grid/CollectionGridDataSource.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/grid/CollectionGridDataSource.java
 Tue Feb 26 11:21:44 2008
@@ -15,8 +15,9 @@
 package org.apache.tapestry.internal.grid;
 
 import org.apache.tapestry.PropertyConduit;
-import org.apache.tapestry.beaneditor.PropertyModel;
+import org.apache.tapestry.grid.ColumnSort;
 import org.apache.tapestry.grid.GridDataSource;
+import org.apache.tapestry.grid.SortConstraint;
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
 import static org.apache.tapestry.ioc.internal.util.Defense.notNull;
 
@@ -44,53 +45,57 @@
         return _list.size();
     }
 
-    @SuppressWarnings("unchecked")
-    public void prepare(int startIndex, int endIndex, PropertyModel sortModel, 
final boolean ascending)
+    public void prepare(int startIndex, int endIndex, List<SortConstraint> 
sortConstraints)
     {
-        if (sortModel == null) return;
+        for (SortConstraint constraint : sortConstraints)
+        {
+            final ColumnSort sort = constraint.getColumnSort();
 
-        final PropertyConduit conduit = sortModel.getConduit();
+            if (sort == ColumnSort.UNSORTED) continue;
 
-        final Comparator valueComparator = new Comparator<Comparable>()
-        {
-            public int compare(Comparable o1, Comparable o2)
+            final PropertyConduit conduit = 
constraint.getPropertyModel().getConduit();
+
+            final Comparator valueComparator = new Comparator<Comparable>()
             {
-                // Simplify comparison, and handle case where both are nulls.
+                public int compare(Comparable o1, Comparable o2)
+                {
+                    // Simplify comparison, and handle case where both are 
nulls.
 
-                if (o1 == o2) return 0;
+                    if (o1 == o2) return 0;
 
-                if (o2 == null) return 1;
+                    if (o2 == null) return 1;
 
-                if (o1 == null) return -1;
+                    if (o1 == null) return -1;
 
-                return o1.compareTo(o2);
-            }
-        };
+                    return o1.compareTo(o2);
+                }
+            };
 
-        final Comparator rowComparator = new Comparator()
-        {
-            public int compare(Object row1, Object row2)
+            final Comparator rowComparator = new Comparator()
             {
-                Comparable value1 = (Comparable) conduit.get(row1);
-                Comparable value2 = (Comparable) conduit.get(row2);
-
-                return valueComparator.compare(value1, value2);
-            }
-        };
+                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)
+            final Comparator reverseComparator = new Comparator()
             {
-                int modifier = ascending ? 1 : -1;
-
-                return modifier * rowComparator.compare(o1, o2);
-            }
-        };
+                public int compare(Object o1, Object o2)
+                {
+                    int modifier = sort == ColumnSort.ASCENDING ? 1 : -1;
+
+                    return modifier * rowComparator.compare(o1, o2);
+                }
+            };
 
-        // We can freely sort this list because its just a copy.
+            // We can freely sort this list because its just a copy.
 
-        Collections.sort(_list, reverseComparator);
+            Collections.sort(_list, reverseComparator);
+        }
     }
 
     /**

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/grid/NullDataSource.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/grid/NullDataSource.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/grid/NullDataSource.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/grid/NullDataSource.java
 Tue Feb 26 11:21:44 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -14,11 +14,14 @@
 
 package org.apache.tapestry.internal.grid;
 
-import org.apache.tapestry.beaneditor.PropertyModel;
 import org.apache.tapestry.grid.GridDataSource;
+import org.apache.tapestry.grid.SortConstraint;
+
+import java.util.List;
 
 /**
- * An implementation of [EMAIL PROTECTED] GridDataSource} used when the value 
null is provided as the source.
+ * An implementation of [EMAIL PROTECTED] 
org.apache.tapestry.grid.GridDataSource} used when the value null is provided 
as the
+ * source.
  */
 public class NullDataSource implements GridDataSource
 {
@@ -32,7 +35,7 @@
         return null;
     }
 
-    public void prepare(int startIndex, int endIndex, PropertyModel sortModel, 
boolean ascending)
+    public void prepare(int startIndex, int endIndex, List<SortConstraint> 
sortConstraints)
     {
     }
 

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/PropertyConduitSource.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/PropertyConduitSource.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/PropertyConduitSource.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/PropertyConduitSource.java
 Tue Feb 26 11:21:44 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -36,7 +36,7 @@
      * Creates a new property conduit instance for the given expression.
      *
      * @param rootClass  the class of the root object to which the expression 
is applied
-     * @param expression
+     * @param expression expression to be evaluated on instances of the root 
class
      * @return RuntimeException if the expression is invalid (poorly formed, 
references non-existent properties, etc.)
      */
     PropertyConduit create(Class rootClass, String expression);

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/beaneditor/BeanEditorStrings.properties
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/beaneditor/BeanEditorStrings.properties?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/beaneditor/BeanEditorStrings.properties
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/beaneditor/BeanEditorStrings.properties
 Tue Feb 26 11:21:44 2008
@@ -1,4 +1,4 @@
-# Copyright 2007 The Apache Software Foundation
+# Copyright 2007, 2008 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.
@@ -13,4 +13,5 @@
 # limitations under the License.
 
 duplicate-property-name=Bean editor model for %s already contains a property 
model for property '%s'.
-unknown-property=Bean editor model for %s does not contain a property named 
'%s'.  Available properties: %s.
\ No newline at end of file
+unknown-property=Bean editor model for %s does not contain a property named 
'%s'.  Available properties: %s.
+unknown-property-id=Bean editor model for %s does not contain a property with 
id '%s'.  Available property ids: %s.
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/site/apt/upgrade.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/site/apt/upgrade.apt?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/site/apt/upgrade.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/site/apt/upgrade.apt Tue Feb 26 
11:21:44 2008
@@ -36,4 +36,11 @@
 * MetaDataLocator
 
   The <<findMeta()>> method on interface 
{{{../apidocs/org/apache/tapestry/services/MetaDataLocator.html}MetaDataLocator}}
-  has changed significantly; it now expands symbols and performs type coercion.
\ No newline at end of file
+  has changed significantly; it now expands symbols and performs type coercion.
+
+* Grid Interfaces
+
+  The {{{../apidocs/org/apache/tapestry/grid/GridModel.html}GridModel}} and
+  the <<<prepare()>>> method of 
+  {{{../apidocs/org/apache/tapestry/grid/GridDataSource.html}GridDataSource}} 
have changed to accomidate
+  the ability to sort using multiple columns.
\ No newline at end of file

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/GridDemo.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/GridDemo.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/GridDemo.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/GridDemo.java
 Tue Feb 26 11:21:44 2008
@@ -47,6 +47,9 @@
         return _library.getTracks();
     }
 
-    void onActionFromSortRating() { _grid.updateSort("rating"); }
+    void onActionFromSortRating()
+    {
+        _grid.getSortModel().updateSort("rating");
+    }
 
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/grid/CollectionGridDataSourceTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/grid/CollectionGridDataSourceTest.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/grid/CollectionGridDataSourceTest.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/grid/CollectionGridDataSourceTest.java
 Tue Feb 26 11:21:44 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -17,6 +17,8 @@
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.beaneditor.BeanModel;
 import org.apache.tapestry.beaneditor.PropertyModel;
+import org.apache.tapestry.grid.ColumnSort;
+import org.apache.tapestry.grid.SortConstraint;
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
 import org.apache.tapestry.ioc.Messages;
 import org.apache.tapestry.services.BeanModelSource;
@@ -25,6 +27,7 @@
 import org.testng.annotations.Test;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 public class CollectionGridDataSourceTest extends InternalBaseTestCase
@@ -107,7 +110,10 @@
 
         int availableRows = _source.getAvailableRows();
 
-        _source.prepare(0, availableRows - 1, propertyModel, ascending);
+        SortConstraint constraint = new SortConstraint(propertyModel, 
ascending ? ColumnSort.ASCENDING : ColumnSort.DESCENDING);
+        List<SortConstraint> constraints = 
Collections.singletonList(constraint);
+
+        _source.prepare(0, availableRows - 1, constraints);
 
         for (int i = 0; i < ids.length; i++)
         {

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/BeanModelSourceImplTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/BeanModelSourceImplTest.java?rev=631344&r1=631343&r2=631344&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/BeanModelSourceImplTest.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/BeanModelSourceImplTest.java
 Tue Feb 26 11:21:44 2008
@@ -305,6 +305,77 @@
     }
 
     @Test
+    public void unknown_property_id()
+    {
+        ComponentResources resources = mockComponentResources();
+        Messages messages = mockMessages();
+
+        train_getMessages(resources, messages);
+        stub_contains(messages, false);
+
+        replay();
+
+        BeanModel model = _source.create(SimpleBean.class, true, resources);
+
+        model.add("shrub.foo()", null);
+
+        try
+        {
+            model.getById("frobozz");
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertEquals(ex.getMessage(),
+                         "Bean editor model for 
org.apache.tapestry.internal.services.SimpleBean does not contain a property 
with id \'frobozz\'.  "
+                                 + "Available property ids: age, firstName, 
lastName, shrubfoo.");
+        }
+
+        verify();
+    }
+
+    @Test
+    public void get_added_property_by_name()
+    {
+        ComponentResources resources = mockComponentResources();
+        Messages messages = mockMessages();
+
+        train_getMessages(resources, messages);
+        stub_contains(messages, false);
+
+        replay();
+
+        BeanModel model = _source.create(SimpleBean.class, true, resources);
+
+        PropertyModel pm = model.add("shrub.foo()", null);
+
+        assertSame(model.get("Shrub.Foo()"), pm);
+
+        verify();
+    }
+
+    @Test
+    public void get_added_property_by_id()
+    {
+        ComponentResources resources = mockComponentResources();
+        Messages messages = mockMessages();
+
+        train_getMessages(resources, messages);
+        stub_contains(messages, false);
+
+        replay();
+
+        BeanModel model = _source.create(SimpleBean.class, true, resources);
+
+        PropertyModel pm = model.add("shrub.foo()", null);
+
+        assertSame(model.getById("ShrubFoo"), pm);
+
+        verify();
+
+    }
+
+    @Test
     public void order_via_annotation()
     {
         ComponentResources resources = mockComponentResources();


Reply via email to