You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@myfaces.apache.org by Mike Kienenberger <mk...@gmail.com> on 2007/03/14 18:26:44 UTC

SortableModel and t:dataTable changes/improvements

I took a look at SortableModel and t:dataTable sorting again last
night.  My requirements in most cases are to simply specify a sort
order in the page code, not to allow end-users to manipulate the sort
order.    From what I can tell, there's no easy way to do this. I
documented the most effective method I could find on the wiki under a
"static sorting" subheading, but even that method leaves unnecessary
links in the column headers.

At the same time, I looked into what it would take to make sorting
cleaner and more user-friendly.

I came up with a subclass of extended dataTable and a replacement
SortableModel that did what I wanted for the most part:

<my:sortableDataTable
	preserveDataModel="true"
        value="#{bean.carList}"
        var="car"
	>
	<f:facet name="comparator">
		<my:propertyComparator
			property="style.color"
			descending="true" />
	</f:facet>
</my:sortableDataTable>

This is based in part on reusing my components for sorting selectItem
lists.   For some reason, couldn't make this work without using
preserveDataModel.   [Strangely enough, doing the same thing with the
current t:dataTable sort attributes didn't require preserveDataModel.]

In any case, a comparator component can be any UIComponent that
implements a ComparatorSource interface (ie, public Comparator
getComparator()), which provides a great deal of flexibility.

The propertyComparator implementation basically does the same thing as
the internal guts of the current SortableModel, but is pluggable.  I
used beanutils in my comparator rather than EL to process the property
expression, which also eliminates the "rowObjectGet" hack.   An "EL
comparator" could be implemented if the EL processing features were
needed.

I think it would be worthwhile to replace the current SortableModel
with a more generic pluggable one.   A good start would be to pull all
of the property-resolving/comparison out of it, and stick it into a
comparator like I did.   setSortCriteria(List criteria) appears to be
misnomer since only the first item in the list is used -- using a
comparator would also solve that issue as you can create
MultipleComparator that takes a list of other comparators and goes
through them in order.

Following is what DataTable looks like to make this work.  Note that
this doesn't handle the current sorting options.

    protected DataModel createDataModel()
    {
        DataModel dataModel = super.createDataModel();

        UIComponent comparatorUIComponent = getComparator();
    	Comparator comparator = null;
        if (null != comparatorUIComponent)
        {
        	if (comparatorUIComponent instanceof ComparatorSource)
        	{
        		comparator =
((ComparatorSource)comparatorUIComponent).getComparator();
        	}
        	else
        	{
        		// TODO: need log error instead
        		throw new RuntimeException("comparatorUIComponent should
implement ComparatorSource");
        	}
        }

        boolean isSortable = null != comparator;

        if (isSortable)
        {
            if (!(dataModel instanceof BaseSortableModel))
            {
                dataModel = new BaseSortableModel(dataModel);
            }

            ((BaseSortableModel)dataModel).setComparator(comparator);
        }

        return dataModel;
    }

After stripping out the comparator stuff from SortableModel, these are
the major changes:

	public void setComparator(Comparator _comparator) {
		this._comparator = _comparator;
		_sort();
	}


    private void _sort()
    {
    	if (null == _comparator)
    	{
            // restore unsorted order:
            _baseIndicesList = _sortedIndicesList = null;
    		return;
    	}
    	
        //TODO: support -1 for rowCount:
        int sz = getRowCount();
        if ((_baseIndicesList == null) || (_baseIndicesList.size() != sz))
        {
            // we do not want to mutate the original data.
            // however, instead of copying the data and sorting the copy,
            // we will create a list of indices into the original data, and
            // sort the indices. This way, when certain rows are made current
            // in this Collection, we can make them current in the underlying
            // DataModel as well.
            _baseIndicesList = new IntList(sz);
        }

        final int rowIndex = _model.getRowIndex();

        _model.setRowIndex(0);
        // Make sure the model has that row 0! (It could be empty.)
        if (_model.isRowAvailable())
        {
            Collections.sort(_baseIndicesList, new
RowDataComparator(_comparator, _model));
            _sortedIndicesList = null;
        }

        _model.setRowIndex(rowIndex);
    }

    protected class RowDataComparator implements Comparator
    {
		private Comparator dataComparator = null;
		private DataModel dataModel = null;
		
		public RowDataComparator(Comparator comparator, DataModel model)
		{
			this.dataComparator = comparator;
			this.dataModel = model;
		}
		
		public int compare(Object arg1, Object arg2) {
			Integer r1 = (Integer)arg1;
			Integer r2 = (Integer)arg2;
			dataModel.setRowIndex(r1.intValue());
	        Object rowData1 = _model.getRowData();
	        dataModel.setRowIndex(r2.intValue());
	        Object rowData2 = _model.getRowData();
	
	        return dataComparator.compare(rowData1, rowData2);
		}
    }


Also, here's how I'd like to improve t:selectItems.  I've had a custom
subclass of f:selectItems of this working for awhile.  Notice how we
can reuse the same propertyComparator component.  This particular
implementation can take a list of comparator children and implicitly
wraps them in a MultipleComparator.   That's not really possible with
a dataTable facet, so we'd want to provide a MultipleComparator
component.

<my:orderedSelectItems value="#{bean.carList}">
    <my:propertyComparator
         property="style.color"
         descending="false" />
</my:orderedSelectItems>

Re: SortableModel and t:dataTable changes/improvements

Posted by Mike Kienenberger <mk...@gmail.com>.
Tomahawk's t:dataTable requires SortableDataModel, which is why that
check is in here.   At some point I'd love to see that requirement
relaxed, but no one has done further work toward that end.

I think the easiest thing to do right now is to subclass HtmlDataTable
and override createDataModel.

This is how I did it.

package test;

import java.util.Comparator;

import javax.faces.component.UIComponent;
import javax.faces.model.DataModel;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.component.html.ext.HtmlDataTable;

/**
 * @author Mike Kienenberger (latest modification by $Author: mlk $)
 * @version $id$
 */
public class SortableHtmlDataTable extends HtmlDataTable
{
    private static final Log log =
LogFactory.getLog(SortableHtmlDataTable.class);

    public static final String COMPARATOR_FACET_NAME = "comparator";

    /**
     * @see org.apache.myfaces.component.html.ext.HtmlDataTableHack#createDataModel()
     */
    protected DataModel createDataModel()
    {
        DataModel dataModel = super.createDataModel();

        UIComponent comparatorUIComponent = getComparator();
    	Comparator comparator = null;
        if (null != comparatorUIComponent)
        {
        	if (comparatorUIComponent instanceof ComparatorSource)
        	{
        		comparator =
((ComparatorSource)comparatorUIComponent).getComparator();
        	}
        	else
        	{
        		// TODO: need log error instead
        		throw new RuntimeException("comparatorUIComponent should
implement ComparatorSource");
        	}
        }

        boolean isSortable = null != comparator;

        if (isSortable)
        {
            if (!(dataModel instanceof BaseSortableModel))
            {
                dataModel = new BaseSortableModel(dataModel);
            }

            ((BaseSortableModel)dataModel).setComparator(comparator);
        }

        return dataModel;
    }

    /**
     * Gets the comparator facet for sorting.
     */
    public UIComponent getComparator() {
        return (UIComponent)getFacets().get(COMPARATOR_FACET_NAME);
    }
    public void setComparator(UIComponent comparator) {
        getFacets().put(COMPARATOR_FACET_NAME, comparator);
    }

    //------------------ GENERATED CODE BEGIN (do not modify!)
--------------------

    public static final String COMPONENT_TYPE = "test.SortableHtmlDataTable";
    public static final String DEFAULT_RENDERER_TYPE =
"org.apache.myfaces.Table";

}


On 11/27/07, CatalinPetrisor <ma...@yahoo.com> wrote:
>
> I can subclass it of course, but because HtmlDataTable (in createDataModel
> method) checks if the DataModel is an instance of SortableDataModel, it will
> actually wrap my extended BaseSortableModel into a SortableModel, that will
> not use my custom defined comparator.
>
> I would expect that HtmlDataTable to use only BaseSortableModel and every
> time a column header link is clicked to notify me by which column the data
> to be sorted.
>
> Or maybe I got it wrong. Could you explain in few words how would you
> implement a custom sortable model starting from BaseSortableModel?
>
> Thanks.
> Catalin
>
>
> Mike Kienenberger wrote:
> >
> > It was left that way to provide identical backward compatible behavior.
> >
> > However, you should be able to subclass (or use) BaseSortableModel
> > instead of the default sortable model.
> >
> > On 11/27/07, CatalinPetrisor <ma...@yahoo.com> wrote:
> >>
> >> That's a very good idea. However, in the latest svn sources the
> >> HtmlDataTable
> >> component still uses SortableModel class to set the current sort column.
> >> Wouldn't be normal to use BaseSortableModel class to allow extensibility?
> >>
> >> Thanks.
> >>
> >>
> >> Mike Kienenberger wrote:
> >> >
> >> > As a first step in this process, I've separated SortableDataModel into
> >> > SortableDataModel (current behavior, final, subclass of
> >> > BaseSortableDataModel) and BaseSortableDataModel (extendable, works on
> >> > Comparators).
> >> >
> >> > I tested all of the simple examples involving dataTable at one point,
> >> > but it's possible that something may have slipped by me that I didn't
> >> > notice.
> >> >
> >> >
> >> > On 3/14/07, Mike Kienenberger <mk...@gmail.com> wrote:
> >> >> I took a look at SortableModel and t:dataTable sorting again last
> >> >> night.  My requirements in most cases are to simply specify a sort
> >> >> order in the page code, not to allow end-users to manipulate the sort
> >> >> order.    From what I can tell, there's no easy way to do this. I
> >> >> documented the most effective method I could find on the wiki under a
> >> >> "static sorting" subheading, but even that method leaves unnecessary
> >> >> links in the column headers.
> >> >>
> >> >> At the same time, I looked into what it would take to make sorting
> >> >> cleaner and more user-friendly.
> >> >>
> >> >> I came up with a subclass of extended dataTable and a replacement
> >> >> SortableModel that did what I wanted for the most part:
> >> >>
> >> >> <my:sortableDataTable
> >> >>         preserveDataModel="true"
> >> >>         value="#{bean.carList}"
> >> >>         var="car"
> >> >>         >
> >> >>         <f:facet name="comparator">
> >> >>                 <my:propertyComparator
> >> >>                         property="style.color"
> >> >>                         descending="true" />
> >> >>         </f:facet>
> >> >> </my:sortableDataTable>
> >> >>
> >> >> This is based in part on reusing my components for sorting selectItem
> >> >> lists.   For some reason, couldn't make this work without using
> >> >> preserveDataModel.   [Strangely enough, doing the same thing with the
> >> >> current t:dataTable sort attributes didn't require preserveDataModel.]
> >> >>
> >> >> In any case, a comparator component can be any UIComponent that
> >> >> implements a ComparatorSource interface (ie, public Comparator
> >> >> getComparator()), which provides a great deal of flexibility.
> >> >>
> >> >> The propertyComparator implementation basically does the same thing as
> >> >> the internal guts of the current SortableModel, but is pluggable.  I
> >> >> used beanutils in my comparator rather than EL to process the property
> >> >> expression, which also eliminates the "rowObjectGet" hack.   An "EL
> >> >> comparator" could be implemented if the EL processing features were
> >> >> needed.
> >> >>
> >> >> I think it would be worthwhile to replace the current SortableModel
> >> >> with a more generic pluggable one.   A good start would be to pull all
> >> >> of the property-resolving/comparison out of it, and stick it into a
> >> >> comparator like I did.   setSortCriteria(List criteria) appears to be
> >> >> misnomer since only the first item in the list is used -- using a
> >> >> comparator would also solve that issue as you can create
> >> >> MultipleComparator that takes a list of other comparators and goes
> >> >> through them in order.
> >> >>
> >> >> Following is what DataTable looks like to make this work.  Note that
> >> >> this doesn't handle the current sorting options.
> >> >>
> >> >>     protected DataModel createDataModel()
> >> >>     {
> >> >>         DataModel dataModel = super.createDataModel();
> >> >>
> >> >>         UIComponent comparatorUIComponent = getComparator();
> >> >>         Comparator comparator = null;
> >> >>         if (null != comparatorUIComponent)
> >> >>         {
> >> >>                 if (comparatorUIComponent instanceof ComparatorSource)
> >> >>                 {
> >> >>                         comparator =
> >> >> ((ComparatorSource)comparatorUIComponent).getComparator();
> >> >>                 }
> >> >>                 else
> >> >>                 {
> >> >>                         // TODO: need log error instead
> >> >>                         throw new
> >> RuntimeException("comparatorUIComponent
> >> >> should
> >> >> implement ComparatorSource");
> >> >>                 }
> >> >>         }
> >> >>
> >> >>         boolean isSortable = null != comparator;
> >> >>
> >> >>         if (isSortable)
> >> >>         {
> >> >>             if (!(dataModel instanceof BaseSortableModel))
> >> >>             {
> >> >>                 dataModel = new BaseSortableModel(dataModel);
> >> >>             }
> >> >>
> >> >>             ((BaseSortableModel)dataModel).setComparator(comparator);
> >> >>         }
> >> >>
> >> >>         return dataModel;
> >> >>     }
> >> >>
> >> >> After stripping out the comparator stuff from SortableModel, these are
> >> >> the major changes:
> >> >>
> >> >>         public void setComparator(Comparator _comparator) {
> >> >>                 this._comparator = _comparator;
> >> >>                 _sort();
> >> >>         }
> >> >>
> >> >>
> >> >>     private void _sort()
> >> >>     {
> >> >>         if (null == _comparator)
> >> >>         {
> >> >>             // restore unsorted order:
> >> >>             _baseIndicesList = _sortedIndicesList = null;
> >> >>                 return;
> >> >>         }
> >> >>
> >> >>         //TODO: support -1 for rowCount:
> >> >>         int sz = getRowCount();
> >> >>         if ((_baseIndicesList == null) || (_baseIndicesList.size() !=
> >> >> sz))
> >> >>         {
> >> >>             // we do not want to mutate the original data.
> >> >>             // however, instead of copying the data and sorting the
> >> copy,
> >> >>             // we will create a list of indices into the original
> >> data,
> >> >> and
> >> >>             // sort the indices. This way, when certain rows are made
> >> >> current
> >> >>             // in this Collection, we can make them current in the
> >> >> underlying
> >> >>             // DataModel as well.
> >> >>             _baseIndicesList = new IntList(sz);
> >> >>         }
> >> >>
> >> >>         final int rowIndex = _model.getRowIndex();
> >> >>
> >> >>         _model.setRowIndex(0);
> >> >>         // Make sure the model has that row 0! (It could be empty.)
> >> >>         if (_model.isRowAvailable())
> >> >>         {
> >> >>             Collections.sort(_baseIndicesList, new
> >> >> RowDataComparator(_comparator, _model));
> >> >>             _sortedIndicesList = null;
> >> >>         }
> >> >>
> >> >>         _model.setRowIndex(rowIndex);
> >> >>     }
> >> >>
> >> >>     protected class RowDataComparator implements Comparator
> >> >>     {
> >> >>                 private Comparator dataComparator = null;
> >> >>                 private DataModel dataModel = null;
> >> >>
> >> >>                 public RowDataComparator(Comparator comparator,
> >> DataModel
> >> >> model)
> >> >>                 {
> >> >>                         this.dataComparator = comparator;
> >> >>                         this.dataModel = model;
> >> >>                 }
> >> >>
> >> >>                 public int compare(Object arg1, Object arg2) {
> >> >>                         Integer r1 = (Integer)arg1;
> >> >>                         Integer r2 = (Integer)arg2;
> >> >>                         dataModel.setRowIndex(r1.intValue());
> >> >>                 Object rowData1 = _model.getRowData();
> >> >>                 dataModel.setRowIndex(r2.intValue());
> >> >>                 Object rowData2 = _model.getRowData();
> >> >>
> >> >>                 return dataComparator.compare(rowData1, rowData2);
> >> >>                 }
> >> >>     }
> >> >>
> >> >>
> >> >> Also, here's how I'd like to improve t:selectItems.  I've had a custom
> >> >> subclass of f:selectItems of this working for awhile.  Notice how we
> >> >> can reuse the same propertyComparator component.  This particular
> >> >> implementation can take a list of comparator children and implicitly
> >> >> wraps them in a MultipleComparator.   That's not really possible with
> >> >> a dataTable facet, so we'd want to provide a MultipleComparator
> >> >> component.
> >> >>
> >> >> <my:orderedSelectItems value="#{bean.carList}">
> >> >>     <my:propertyComparator
> >> >>          property="style.color"
> >> >>          descending="false" />
> >> >> </my:orderedSelectItems>
> >> >>
> >> >
> >> >
> >>
> >> --
> >> View this message in context:
> >> http://www.nabble.com/SortableModel-and-t%3AdataTable-changes-improvements-tf3403639.html#a13967432
> >> Sent from the My Faces - Dev mailing list archive at Nabble.com.
> >>
> >>
> >
> >
>
> --
> View this message in context: http://www.nabble.com/SortableModel-and-t%3AdataTable-changes-improvements-tf3403639.html#a13976924
> Sent from the My Faces - Dev mailing list archive at Nabble.com.
>
>

Re: SortableModel and t:dataTable changes/improvements

Posted by CatalinPetrisor <ma...@yahoo.com>.
I can subclass it of course, but because HtmlDataTable (in createDataModel
method) checks if the DataModel is an instance of SortableDataModel, it will
actually wrap my extended BaseSortableModel into a SortableModel, that will
not use my custom defined comparator. 

I would expect that HtmlDataTable to use only BaseSortableModel and every
time a column header link is clicked to notify me by which column the data
to be sorted. 

Or maybe I got it wrong. Could you explain in few words how would you
implement a custom sortable model starting from BaseSortableModel?

Thanks.
Catalin


Mike Kienenberger wrote:
> 
> It was left that way to provide identical backward compatible behavior.
> 
> However, you should be able to subclass (or use) BaseSortableModel
> instead of the default sortable model.
> 
> On 11/27/07, CatalinPetrisor <ma...@yahoo.com> wrote:
>>
>> That's a very good idea. However, in the latest svn sources the
>> HtmlDataTable
>> component still uses SortableModel class to set the current sort column.
>> Wouldn't be normal to use BaseSortableModel class to allow extensibility?
>>
>> Thanks.
>>
>>
>> Mike Kienenberger wrote:
>> >
>> > As a first step in this process, I've separated SortableDataModel into
>> > SortableDataModel (current behavior, final, subclass of
>> > BaseSortableDataModel) and BaseSortableDataModel (extendable, works on
>> > Comparators).
>> >
>> > I tested all of the simple examples involving dataTable at one point,
>> > but it's possible that something may have slipped by me that I didn't
>> > notice.
>> >
>> >
>> > On 3/14/07, Mike Kienenberger <mk...@gmail.com> wrote:
>> >> I took a look at SortableModel and t:dataTable sorting again last
>> >> night.  My requirements in most cases are to simply specify a sort
>> >> order in the page code, not to allow end-users to manipulate the sort
>> >> order.    From what I can tell, there's no easy way to do this. I
>> >> documented the most effective method I could find on the wiki under a
>> >> "static sorting" subheading, but even that method leaves unnecessary
>> >> links in the column headers.
>> >>
>> >> At the same time, I looked into what it would take to make sorting
>> >> cleaner and more user-friendly.
>> >>
>> >> I came up with a subclass of extended dataTable and a replacement
>> >> SortableModel that did what I wanted for the most part:
>> >>
>> >> <my:sortableDataTable
>> >>         preserveDataModel="true"
>> >>         value="#{bean.carList}"
>> >>         var="car"
>> >>         >
>> >>         <f:facet name="comparator">
>> >>                 <my:propertyComparator
>> >>                         property="style.color"
>> >>                         descending="true" />
>> >>         </f:facet>
>> >> </my:sortableDataTable>
>> >>
>> >> This is based in part on reusing my components for sorting selectItem
>> >> lists.   For some reason, couldn't make this work without using
>> >> preserveDataModel.   [Strangely enough, doing the same thing with the
>> >> current t:dataTable sort attributes didn't require preserveDataModel.]
>> >>
>> >> In any case, a comparator component can be any UIComponent that
>> >> implements a ComparatorSource interface (ie, public Comparator
>> >> getComparator()), which provides a great deal of flexibility.
>> >>
>> >> The propertyComparator implementation basically does the same thing as
>> >> the internal guts of the current SortableModel, but is pluggable.  I
>> >> used beanutils in my comparator rather than EL to process the property
>> >> expression, which also eliminates the "rowObjectGet" hack.   An "EL
>> >> comparator" could be implemented if the EL processing features were
>> >> needed.
>> >>
>> >> I think it would be worthwhile to replace the current SortableModel
>> >> with a more generic pluggable one.   A good start would be to pull all
>> >> of the property-resolving/comparison out of it, and stick it into a
>> >> comparator like I did.   setSortCriteria(List criteria) appears to be
>> >> misnomer since only the first item in the list is used -- using a
>> >> comparator would also solve that issue as you can create
>> >> MultipleComparator that takes a list of other comparators and goes
>> >> through them in order.
>> >>
>> >> Following is what DataTable looks like to make this work.  Note that
>> >> this doesn't handle the current sorting options.
>> >>
>> >>     protected DataModel createDataModel()
>> >>     {
>> >>         DataModel dataModel = super.createDataModel();
>> >>
>> >>         UIComponent comparatorUIComponent = getComparator();
>> >>         Comparator comparator = null;
>> >>         if (null != comparatorUIComponent)
>> >>         {
>> >>                 if (comparatorUIComponent instanceof ComparatorSource)
>> >>                 {
>> >>                         comparator =
>> >> ((ComparatorSource)comparatorUIComponent).getComparator();
>> >>                 }
>> >>                 else
>> >>                 {
>> >>                         // TODO: need log error instead
>> >>                         throw new
>> RuntimeException("comparatorUIComponent
>> >> should
>> >> implement ComparatorSource");
>> >>                 }
>> >>         }
>> >>
>> >>         boolean isSortable = null != comparator;
>> >>
>> >>         if (isSortable)
>> >>         {
>> >>             if (!(dataModel instanceof BaseSortableModel))
>> >>             {
>> >>                 dataModel = new BaseSortableModel(dataModel);
>> >>             }
>> >>
>> >>             ((BaseSortableModel)dataModel).setComparator(comparator);
>> >>         }
>> >>
>> >>         return dataModel;
>> >>     }
>> >>
>> >> After stripping out the comparator stuff from SortableModel, these are
>> >> the major changes:
>> >>
>> >>         public void setComparator(Comparator _comparator) {
>> >>                 this._comparator = _comparator;
>> >>                 _sort();
>> >>         }
>> >>
>> >>
>> >>     private void _sort()
>> >>     {
>> >>         if (null == _comparator)
>> >>         {
>> >>             // restore unsorted order:
>> >>             _baseIndicesList = _sortedIndicesList = null;
>> >>                 return;
>> >>         }
>> >>
>> >>         //TODO: support -1 for rowCount:
>> >>         int sz = getRowCount();
>> >>         if ((_baseIndicesList == null) || (_baseIndicesList.size() !=
>> >> sz))
>> >>         {
>> >>             // we do not want to mutate the original data.
>> >>             // however, instead of copying the data and sorting the
>> copy,
>> >>             // we will create a list of indices into the original
>> data,
>> >> and
>> >>             // sort the indices. This way, when certain rows are made
>> >> current
>> >>             // in this Collection, we can make them current in the
>> >> underlying
>> >>             // DataModel as well.
>> >>             _baseIndicesList = new IntList(sz);
>> >>         }
>> >>
>> >>         final int rowIndex = _model.getRowIndex();
>> >>
>> >>         _model.setRowIndex(0);
>> >>         // Make sure the model has that row 0! (It could be empty.)
>> >>         if (_model.isRowAvailable())
>> >>         {
>> >>             Collections.sort(_baseIndicesList, new
>> >> RowDataComparator(_comparator, _model));
>> >>             _sortedIndicesList = null;
>> >>         }
>> >>
>> >>         _model.setRowIndex(rowIndex);
>> >>     }
>> >>
>> >>     protected class RowDataComparator implements Comparator
>> >>     {
>> >>                 private Comparator dataComparator = null;
>> >>                 private DataModel dataModel = null;
>> >>
>> >>                 public RowDataComparator(Comparator comparator,
>> DataModel
>> >> model)
>> >>                 {
>> >>                         this.dataComparator = comparator;
>> >>                         this.dataModel = model;
>> >>                 }
>> >>
>> >>                 public int compare(Object arg1, Object arg2) {
>> >>                         Integer r1 = (Integer)arg1;
>> >>                         Integer r2 = (Integer)arg2;
>> >>                         dataModel.setRowIndex(r1.intValue());
>> >>                 Object rowData1 = _model.getRowData();
>> >>                 dataModel.setRowIndex(r2.intValue());
>> >>                 Object rowData2 = _model.getRowData();
>> >>
>> >>                 return dataComparator.compare(rowData1, rowData2);
>> >>                 }
>> >>     }
>> >>
>> >>
>> >> Also, here's how I'd like to improve t:selectItems.  I've had a custom
>> >> subclass of f:selectItems of this working for awhile.  Notice how we
>> >> can reuse the same propertyComparator component.  This particular
>> >> implementation can take a list of comparator children and implicitly
>> >> wraps them in a MultipleComparator.   That's not really possible with
>> >> a dataTable facet, so we'd want to provide a MultipleComparator
>> >> component.
>> >>
>> >> <my:orderedSelectItems value="#{bean.carList}">
>> >>     <my:propertyComparator
>> >>          property="style.color"
>> >>          descending="false" />
>> >> </my:orderedSelectItems>
>> >>
>> >
>> >
>>
>> --
>> View this message in context:
>> http://www.nabble.com/SortableModel-and-t%3AdataTable-changes-improvements-tf3403639.html#a13967432
>> Sent from the My Faces - Dev mailing list archive at Nabble.com.
>>
>>
> 
> 

-- 
View this message in context: http://www.nabble.com/SortableModel-and-t%3AdataTable-changes-improvements-tf3403639.html#a13976924
Sent from the My Faces - Dev mailing list archive at Nabble.com.


Re: SortableModel and t:dataTable changes/improvements

Posted by Mike Kienenberger <mk...@gmail.com>.
It was left that way to provide identical backward compatible behavior.

However, you should be able to subclass (or use) BaseSortableModel
instead of the default sortable model.

On 11/27/07, CatalinPetrisor <ma...@yahoo.com> wrote:
>
> That's a very good idea. However, in the latest svn sources the HtmlDataTable
> component still uses SortableModel class to set the current sort column.
> Wouldn't be normal to use BaseSortableModel class to allow extensibility?
>
> Thanks.
>
>
> Mike Kienenberger wrote:
> >
> > As a first step in this process, I've separated SortableDataModel into
> > SortableDataModel (current behavior, final, subclass of
> > BaseSortableDataModel) and BaseSortableDataModel (extendable, works on
> > Comparators).
> >
> > I tested all of the simple examples involving dataTable at one point,
> > but it's possible that something may have slipped by me that I didn't
> > notice.
> >
> >
> > On 3/14/07, Mike Kienenberger <mk...@gmail.com> wrote:
> >> I took a look at SortableModel and t:dataTable sorting again last
> >> night.  My requirements in most cases are to simply specify a sort
> >> order in the page code, not to allow end-users to manipulate the sort
> >> order.    From what I can tell, there's no easy way to do this. I
> >> documented the most effective method I could find on the wiki under a
> >> "static sorting" subheading, but even that method leaves unnecessary
> >> links in the column headers.
> >>
> >> At the same time, I looked into what it would take to make sorting
> >> cleaner and more user-friendly.
> >>
> >> I came up with a subclass of extended dataTable and a replacement
> >> SortableModel that did what I wanted for the most part:
> >>
> >> <my:sortableDataTable
> >>         preserveDataModel="true"
> >>         value="#{bean.carList}"
> >>         var="car"
> >>         >
> >>         <f:facet name="comparator">
> >>                 <my:propertyComparator
> >>                         property="style.color"
> >>                         descending="true" />
> >>         </f:facet>
> >> </my:sortableDataTable>
> >>
> >> This is based in part on reusing my components for sorting selectItem
> >> lists.   For some reason, couldn't make this work without using
> >> preserveDataModel.   [Strangely enough, doing the same thing with the
> >> current t:dataTable sort attributes didn't require preserveDataModel.]
> >>
> >> In any case, a comparator component can be any UIComponent that
> >> implements a ComparatorSource interface (ie, public Comparator
> >> getComparator()), which provides a great deal of flexibility.
> >>
> >> The propertyComparator implementation basically does the same thing as
> >> the internal guts of the current SortableModel, but is pluggable.  I
> >> used beanutils in my comparator rather than EL to process the property
> >> expression, which also eliminates the "rowObjectGet" hack.   An "EL
> >> comparator" could be implemented if the EL processing features were
> >> needed.
> >>
> >> I think it would be worthwhile to replace the current SortableModel
> >> with a more generic pluggable one.   A good start would be to pull all
> >> of the property-resolving/comparison out of it, and stick it into a
> >> comparator like I did.   setSortCriteria(List criteria) appears to be
> >> misnomer since only the first item in the list is used -- using a
> >> comparator would also solve that issue as you can create
> >> MultipleComparator that takes a list of other comparators and goes
> >> through them in order.
> >>
> >> Following is what DataTable looks like to make this work.  Note that
> >> this doesn't handle the current sorting options.
> >>
> >>     protected DataModel createDataModel()
> >>     {
> >>         DataModel dataModel = super.createDataModel();
> >>
> >>         UIComponent comparatorUIComponent = getComparator();
> >>         Comparator comparator = null;
> >>         if (null != comparatorUIComponent)
> >>         {
> >>                 if (comparatorUIComponent instanceof ComparatorSource)
> >>                 {
> >>                         comparator =
> >> ((ComparatorSource)comparatorUIComponent).getComparator();
> >>                 }
> >>                 else
> >>                 {
> >>                         // TODO: need log error instead
> >>                         throw new RuntimeException("comparatorUIComponent
> >> should
> >> implement ComparatorSource");
> >>                 }
> >>         }
> >>
> >>         boolean isSortable = null != comparator;
> >>
> >>         if (isSortable)
> >>         {
> >>             if (!(dataModel instanceof BaseSortableModel))
> >>             {
> >>                 dataModel = new BaseSortableModel(dataModel);
> >>             }
> >>
> >>             ((BaseSortableModel)dataModel).setComparator(comparator);
> >>         }
> >>
> >>         return dataModel;
> >>     }
> >>
> >> After stripping out the comparator stuff from SortableModel, these are
> >> the major changes:
> >>
> >>         public void setComparator(Comparator _comparator) {
> >>                 this._comparator = _comparator;
> >>                 _sort();
> >>         }
> >>
> >>
> >>     private void _sort()
> >>     {
> >>         if (null == _comparator)
> >>         {
> >>             // restore unsorted order:
> >>             _baseIndicesList = _sortedIndicesList = null;
> >>                 return;
> >>         }
> >>
> >>         //TODO: support -1 for rowCount:
> >>         int sz = getRowCount();
> >>         if ((_baseIndicesList == null) || (_baseIndicesList.size() !=
> >> sz))
> >>         {
> >>             // we do not want to mutate the original data.
> >>             // however, instead of copying the data and sorting the copy,
> >>             // we will create a list of indices into the original data,
> >> and
> >>             // sort the indices. This way, when certain rows are made
> >> current
> >>             // in this Collection, we can make them current in the
> >> underlying
> >>             // DataModel as well.
> >>             _baseIndicesList = new IntList(sz);
> >>         }
> >>
> >>         final int rowIndex = _model.getRowIndex();
> >>
> >>         _model.setRowIndex(0);
> >>         // Make sure the model has that row 0! (It could be empty.)
> >>         if (_model.isRowAvailable())
> >>         {
> >>             Collections.sort(_baseIndicesList, new
> >> RowDataComparator(_comparator, _model));
> >>             _sortedIndicesList = null;
> >>         }
> >>
> >>         _model.setRowIndex(rowIndex);
> >>     }
> >>
> >>     protected class RowDataComparator implements Comparator
> >>     {
> >>                 private Comparator dataComparator = null;
> >>                 private DataModel dataModel = null;
> >>
> >>                 public RowDataComparator(Comparator comparator, DataModel
> >> model)
> >>                 {
> >>                         this.dataComparator = comparator;
> >>                         this.dataModel = model;
> >>                 }
> >>
> >>                 public int compare(Object arg1, Object arg2) {
> >>                         Integer r1 = (Integer)arg1;
> >>                         Integer r2 = (Integer)arg2;
> >>                         dataModel.setRowIndex(r1.intValue());
> >>                 Object rowData1 = _model.getRowData();
> >>                 dataModel.setRowIndex(r2.intValue());
> >>                 Object rowData2 = _model.getRowData();
> >>
> >>                 return dataComparator.compare(rowData1, rowData2);
> >>                 }
> >>     }
> >>
> >>
> >> Also, here's how I'd like to improve t:selectItems.  I've had a custom
> >> subclass of f:selectItems of this working for awhile.  Notice how we
> >> can reuse the same propertyComparator component.  This particular
> >> implementation can take a list of comparator children and implicitly
> >> wraps them in a MultipleComparator.   That's not really possible with
> >> a dataTable facet, so we'd want to provide a MultipleComparator
> >> component.
> >>
> >> <my:orderedSelectItems value="#{bean.carList}">
> >>     <my:propertyComparator
> >>          property="style.color"
> >>          descending="false" />
> >> </my:orderedSelectItems>
> >>
> >
> >
>
> --
> View this message in context: http://www.nabble.com/SortableModel-and-t%3AdataTable-changes-improvements-tf3403639.html#a13967432
> Sent from the My Faces - Dev mailing list archive at Nabble.com.
>
>

Re: SortableModel and t:dataTable changes/improvements

Posted by CatalinPetrisor <ma...@yahoo.com>.
That's a very good idea. However, in the latest svn sources the HtmlDataTable
component still uses SortableModel class to set the current sort column.
Wouldn't be normal to use BaseSortableModel class to allow extensibility?

Thanks.


Mike Kienenberger wrote:
> 
> As a first step in this process, I've separated SortableDataModel into
> SortableDataModel (current behavior, final, subclass of
> BaseSortableDataModel) and BaseSortableDataModel (extendable, works on
> Comparators).
> 
> I tested all of the simple examples involving dataTable at one point,
> but it's possible that something may have slipped by me that I didn't
> notice.
> 
> 
> On 3/14/07, Mike Kienenberger <mk...@gmail.com> wrote:
>> I took a look at SortableModel and t:dataTable sorting again last
>> night.  My requirements in most cases are to simply specify a sort
>> order in the page code, not to allow end-users to manipulate the sort
>> order.    From what I can tell, there's no easy way to do this. I
>> documented the most effective method I could find on the wiki under a
>> "static sorting" subheading, but even that method leaves unnecessary
>> links in the column headers.
>>
>> At the same time, I looked into what it would take to make sorting
>> cleaner and more user-friendly.
>>
>> I came up with a subclass of extended dataTable and a replacement
>> SortableModel that did what I wanted for the most part:
>>
>> <my:sortableDataTable
>>         preserveDataModel="true"
>>         value="#{bean.carList}"
>>         var="car"
>>         >
>>         <f:facet name="comparator">
>>                 <my:propertyComparator
>>                         property="style.color"
>>                         descending="true" />
>>         </f:facet>
>> </my:sortableDataTable>
>>
>> This is based in part on reusing my components for sorting selectItem
>> lists.   For some reason, couldn't make this work without using
>> preserveDataModel.   [Strangely enough, doing the same thing with the
>> current t:dataTable sort attributes didn't require preserveDataModel.]
>>
>> In any case, a comparator component can be any UIComponent that
>> implements a ComparatorSource interface (ie, public Comparator
>> getComparator()), which provides a great deal of flexibility.
>>
>> The propertyComparator implementation basically does the same thing as
>> the internal guts of the current SortableModel, but is pluggable.  I
>> used beanutils in my comparator rather than EL to process the property
>> expression, which also eliminates the "rowObjectGet" hack.   An "EL
>> comparator" could be implemented if the EL processing features were
>> needed.
>>
>> I think it would be worthwhile to replace the current SortableModel
>> with a more generic pluggable one.   A good start would be to pull all
>> of the property-resolving/comparison out of it, and stick it into a
>> comparator like I did.   setSortCriteria(List criteria) appears to be
>> misnomer since only the first item in the list is used -- using a
>> comparator would also solve that issue as you can create
>> MultipleComparator that takes a list of other comparators and goes
>> through them in order.
>>
>> Following is what DataTable looks like to make this work.  Note that
>> this doesn't handle the current sorting options.
>>
>>     protected DataModel createDataModel()
>>     {
>>         DataModel dataModel = super.createDataModel();
>>
>>         UIComponent comparatorUIComponent = getComparator();
>>         Comparator comparator = null;
>>         if (null != comparatorUIComponent)
>>         {
>>                 if (comparatorUIComponent instanceof ComparatorSource)
>>                 {
>>                         comparator =
>> ((ComparatorSource)comparatorUIComponent).getComparator();
>>                 }
>>                 else
>>                 {
>>                         // TODO: need log error instead
>>                         throw new RuntimeException("comparatorUIComponent
>> should
>> implement ComparatorSource");
>>                 }
>>         }
>>
>>         boolean isSortable = null != comparator;
>>
>>         if (isSortable)
>>         {
>>             if (!(dataModel instanceof BaseSortableModel))
>>             {
>>                 dataModel = new BaseSortableModel(dataModel);
>>             }
>>
>>             ((BaseSortableModel)dataModel).setComparator(comparator);
>>         }
>>
>>         return dataModel;
>>     }
>>
>> After stripping out the comparator stuff from SortableModel, these are
>> the major changes:
>>
>>         public void setComparator(Comparator _comparator) {
>>                 this._comparator = _comparator;
>>                 _sort();
>>         }
>>
>>
>>     private void _sort()
>>     {
>>         if (null == _comparator)
>>         {
>>             // restore unsorted order:
>>             _baseIndicesList = _sortedIndicesList = null;
>>                 return;
>>         }
>>
>>         //TODO: support -1 for rowCount:
>>         int sz = getRowCount();
>>         if ((_baseIndicesList == null) || (_baseIndicesList.size() !=
>> sz))
>>         {
>>             // we do not want to mutate the original data.
>>             // however, instead of copying the data and sorting the copy,
>>             // we will create a list of indices into the original data,
>> and
>>             // sort the indices. This way, when certain rows are made
>> current
>>             // in this Collection, we can make them current in the
>> underlying
>>             // DataModel as well.
>>             _baseIndicesList = new IntList(sz);
>>         }
>>
>>         final int rowIndex = _model.getRowIndex();
>>
>>         _model.setRowIndex(0);
>>         // Make sure the model has that row 0! (It could be empty.)
>>         if (_model.isRowAvailable())
>>         {
>>             Collections.sort(_baseIndicesList, new
>> RowDataComparator(_comparator, _model));
>>             _sortedIndicesList = null;
>>         }
>>
>>         _model.setRowIndex(rowIndex);
>>     }
>>
>>     protected class RowDataComparator implements Comparator
>>     {
>>                 private Comparator dataComparator = null;
>>                 private DataModel dataModel = null;
>>
>>                 public RowDataComparator(Comparator comparator, DataModel
>> model)
>>                 {
>>                         this.dataComparator = comparator;
>>                         this.dataModel = model;
>>                 }
>>
>>                 public int compare(Object arg1, Object arg2) {
>>                         Integer r1 = (Integer)arg1;
>>                         Integer r2 = (Integer)arg2;
>>                         dataModel.setRowIndex(r1.intValue());
>>                 Object rowData1 = _model.getRowData();
>>                 dataModel.setRowIndex(r2.intValue());
>>                 Object rowData2 = _model.getRowData();
>>
>>                 return dataComparator.compare(rowData1, rowData2);
>>                 }
>>     }
>>
>>
>> Also, here's how I'd like to improve t:selectItems.  I've had a custom
>> subclass of f:selectItems of this working for awhile.  Notice how we
>> can reuse the same propertyComparator component.  This particular
>> implementation can take a list of comparator children and implicitly
>> wraps them in a MultipleComparator.   That's not really possible with
>> a dataTable facet, so we'd want to provide a MultipleComparator
>> component.
>>
>> <my:orderedSelectItems value="#{bean.carList}">
>>     <my:propertyComparator
>>          property="style.color"
>>          descending="false" />
>> </my:orderedSelectItems>
>>
> 
> 

-- 
View this message in context: http://www.nabble.com/SortableModel-and-t%3AdataTable-changes-improvements-tf3403639.html#a13967432
Sent from the My Faces - Dev mailing list archive at Nabble.com.


Re: SortableModel and t:dataTable changes/improvements

Posted by Mike Kienenberger <mk...@gmail.com>.
As a first step in this process, I've separated SortableDataModel into
SortableDataModel (current behavior, final, subclass of
BaseSortableDataModel) and BaseSortableDataModel (extendable, works on
Comparators).

I tested all of the simple examples involving dataTable at one point,
but it's possible that something may have slipped by me that I didn't
notice.


On 3/14/07, Mike Kienenberger <mk...@gmail.com> wrote:
> I took a look at SortableModel and t:dataTable sorting again last
> night.  My requirements in most cases are to simply specify a sort
> order in the page code, not to allow end-users to manipulate the sort
> order.    From what I can tell, there's no easy way to do this. I
> documented the most effective method I could find on the wiki under a
> "static sorting" subheading, but even that method leaves unnecessary
> links in the column headers.
>
> At the same time, I looked into what it would take to make sorting
> cleaner and more user-friendly.
>
> I came up with a subclass of extended dataTable and a replacement
> SortableModel that did what I wanted for the most part:
>
> <my:sortableDataTable
>         preserveDataModel="true"
>         value="#{bean.carList}"
>         var="car"
>         >
>         <f:facet name="comparator">
>                 <my:propertyComparator
>                         property="style.color"
>                         descending="true" />
>         </f:facet>
> </my:sortableDataTable>
>
> This is based in part on reusing my components for sorting selectItem
> lists.   For some reason, couldn't make this work without using
> preserveDataModel.   [Strangely enough, doing the same thing with the
> current t:dataTable sort attributes didn't require preserveDataModel.]
>
> In any case, a comparator component can be any UIComponent that
> implements a ComparatorSource interface (ie, public Comparator
> getComparator()), which provides a great deal of flexibility.
>
> The propertyComparator implementation basically does the same thing as
> the internal guts of the current SortableModel, but is pluggable.  I
> used beanutils in my comparator rather than EL to process the property
> expression, which also eliminates the "rowObjectGet" hack.   An "EL
> comparator" could be implemented if the EL processing features were
> needed.
>
> I think it would be worthwhile to replace the current SortableModel
> with a more generic pluggable one.   A good start would be to pull all
> of the property-resolving/comparison out of it, and stick it into a
> comparator like I did.   setSortCriteria(List criteria) appears to be
> misnomer since only the first item in the list is used -- using a
> comparator would also solve that issue as you can create
> MultipleComparator that takes a list of other comparators and goes
> through them in order.
>
> Following is what DataTable looks like to make this work.  Note that
> this doesn't handle the current sorting options.
>
>     protected DataModel createDataModel()
>     {
>         DataModel dataModel = super.createDataModel();
>
>         UIComponent comparatorUIComponent = getComparator();
>         Comparator comparator = null;
>         if (null != comparatorUIComponent)
>         {
>                 if (comparatorUIComponent instanceof ComparatorSource)
>                 {
>                         comparator =
> ((ComparatorSource)comparatorUIComponent).getComparator();
>                 }
>                 else
>                 {
>                         // TODO: need log error instead
>                         throw new RuntimeException("comparatorUIComponent should
> implement ComparatorSource");
>                 }
>         }
>
>         boolean isSortable = null != comparator;
>
>         if (isSortable)
>         {
>             if (!(dataModel instanceof BaseSortableModel))
>             {
>                 dataModel = new BaseSortableModel(dataModel);
>             }
>
>             ((BaseSortableModel)dataModel).setComparator(comparator);
>         }
>
>         return dataModel;
>     }
>
> After stripping out the comparator stuff from SortableModel, these are
> the major changes:
>
>         public void setComparator(Comparator _comparator) {
>                 this._comparator = _comparator;
>                 _sort();
>         }
>
>
>     private void _sort()
>     {
>         if (null == _comparator)
>         {
>             // restore unsorted order:
>             _baseIndicesList = _sortedIndicesList = null;
>                 return;
>         }
>
>         //TODO: support -1 for rowCount:
>         int sz = getRowCount();
>         if ((_baseIndicesList == null) || (_baseIndicesList.size() != sz))
>         {
>             // we do not want to mutate the original data.
>             // however, instead of copying the data and sorting the copy,
>             // we will create a list of indices into the original data, and
>             // sort the indices. This way, when certain rows are made current
>             // in this Collection, we can make them current in the underlying
>             // DataModel as well.
>             _baseIndicesList = new IntList(sz);
>         }
>
>         final int rowIndex = _model.getRowIndex();
>
>         _model.setRowIndex(0);
>         // Make sure the model has that row 0! (It could be empty.)
>         if (_model.isRowAvailable())
>         {
>             Collections.sort(_baseIndicesList, new
> RowDataComparator(_comparator, _model));
>             _sortedIndicesList = null;
>         }
>
>         _model.setRowIndex(rowIndex);
>     }
>
>     protected class RowDataComparator implements Comparator
>     {
>                 private Comparator dataComparator = null;
>                 private DataModel dataModel = null;
>
>                 public RowDataComparator(Comparator comparator, DataModel model)
>                 {
>                         this.dataComparator = comparator;
>                         this.dataModel = model;
>                 }
>
>                 public int compare(Object arg1, Object arg2) {
>                         Integer r1 = (Integer)arg1;
>                         Integer r2 = (Integer)arg2;
>                         dataModel.setRowIndex(r1.intValue());
>                 Object rowData1 = _model.getRowData();
>                 dataModel.setRowIndex(r2.intValue());
>                 Object rowData2 = _model.getRowData();
>
>                 return dataComparator.compare(rowData1, rowData2);
>                 }
>     }
>
>
> Also, here's how I'd like to improve t:selectItems.  I've had a custom
> subclass of f:selectItems of this working for awhile.  Notice how we
> can reuse the same propertyComparator component.  This particular
> implementation can take a list of comparator children and implicitly
> wraps them in a MultipleComparator.   That's not really possible with
> a dataTable facet, so we'd want to provide a MultipleComparator
> component.
>
> <my:orderedSelectItems value="#{bean.carList}">
>     <my:propertyComparator
>          property="style.color"
>          descending="false" />
> </my:orderedSelectItems>
>

Re: SortableModel and t:dataTable changes/improvements

Posted by Mike Kienenberger <mk...@gmail.com>.
If you're trying to say that the current sorting code is a bit odd,
I'd agree :-)

I think it needs to be rethought and rewritten.

Some of the things I suspect:
- You cannot have a sorted display without creating user-clickable
sortable headers.
- You cannot specify a list of sort criteria, even though the API
indicates it takes a list.

I haven't addressed any of this, but I think I've made it easier to do
so by providing a more generic BaseSortableModel.

My own proposed sorting api bypasses all of the existing SortableModel
code.   See either the JIRA issue or the original message quoted below
in this thread.


On 3/30/07, Zdeněk Sochor <zd...@ataco.cz> wrote:
> Not a problem having discussion here, Mike ;)
>
> By looking on HtmlDataTable i found weird thing dealing with sorting:
>
> setSortProperty method is NOT called with sortColumn property ->
> if (isSortable && getSortProperty() != null) fails for table w/o column
> with defaultSorted [line 877]->
> NO SortCriterion ever made ->
>
> NOT SORTED data in model :(
>
> The same goes for iteration in encodeBegin(FacesContext).
>
> Zdenek


On 3/14/07, Mike Kienenberger <mk...@gmail.com> wrote:
> I took a look at SortableModel and t:dataTable sorting again last
> night.  My requirements in most cases are to simply specify a sort
> order in the page code, not to allow end-users to manipulate the sort
> order.    From what I can tell, there's no easy way to do this. I
> documented the most effective method I could find on the wiki under a
> "static sorting" subheading, but even that method leaves unnecessary
> links in the column headers.
>
> At the same time, I looked into what it would take to make sorting
> cleaner and more user-friendly.
>
> I came up with a subclass of extended dataTable and a replacement
> SortableModel that did what I wanted for the most part:
>
> <my:sortableDataTable
>         preserveDataModel="true"
>         value="#{bean.carList}"
>         var="car"
>         >
>         <f:facet name="comparator">
>                 <my:propertyComparator
>                         property="style.color"
>                         descending="true" />
>         </f:facet>
> </my:sortableDataTable>
>
> This is based in part on reusing my components for sorting selectItem
> lists.   For some reason, couldn't make this work without using
> preserveDataModel.   [Strangely enough, doing the same thing with the
> current t:dataTable sort attributes didn't require preserveDataModel.]
>
> In any case, a comparator component can be any UIComponent that
> implements a ComparatorSource interface (ie, public Comparator
> getComparator()), which provides a great deal of flexibility.
>
> The propertyComparator implementation basically does the same thing as
> the internal guts of the current SortableModel, but is pluggable.  I
> used beanutils in my comparator rather than EL to process the property
> expression, which also eliminates the "rowObjectGet" hack.   An "EL
> comparator" could be implemented if the EL processing features were
> needed.
>
> I think it would be worthwhile to replace the current SortableModel
> with a more generic pluggable one.   A good start would be to pull all
> of the property-resolving/comparison out of it, and stick it into a
> comparator like I did.   setSortCriteria(List criteria) appears to be
> misnomer since only the first item in the list is used -- using a
> comparator would also solve that issue as you can create
> MultipleComparator that takes a list of other comparators and goes
> through them in order.
>
> Following is what DataTable looks like to make this work.  Note that
> this doesn't handle the current sorting options.
>
>     protected DataModel createDataModel()
>     {
>         DataModel dataModel = super.createDataModel();
>
>         UIComponent comparatorUIComponent = getComparator();
>         Comparator comparator = null;
>         if (null != comparatorUIComponent)
>         {
>                 if (comparatorUIComponent instanceof ComparatorSource)
>                 {
>                         comparator =
> ((ComparatorSource)comparatorUIComponent).getComparator();
>                 }
>                 else
>                 {
>                         // TODO: need log error instead
>                         throw new RuntimeException("comparatorUIComponent should
> implement ComparatorSource");
>                 }
>         }
>
>         boolean isSortable = null != comparator;
>
>         if (isSortable)
>         {
>             if (!(dataModel instanceof BaseSortableModel))
>             {
>                 dataModel = new BaseSortableModel(dataModel);
>             }
>
>             ((BaseSortableModel)dataModel).setComparator(comparator);
>         }
>
>         return dataModel;
>     }
>
> After stripping out the comparator stuff from SortableModel, these are
> the major changes:
>
>         public void setComparator(Comparator _comparator) {
>                 this._comparator = _comparator;
>                 _sort();
>         }
>
>
>     private void _sort()
>     {
>         if (null == _comparator)
>         {
>             // restore unsorted order:
>             _baseIndicesList = _sortedIndicesList = null;
>                 return;
>         }
>
>         //TODO: support -1 for rowCount:
>         int sz = getRowCount();
>         if ((_baseIndicesList == null) || (_baseIndicesList.size() != sz))
>         {
>             // we do not want to mutate the original data.
>             // however, instead of copying the data and sorting the copy,
>             // we will create a list of indices into the original data, and
>             // sort the indices. This way, when certain rows are made current
>             // in this Collection, we can make them current in the underlying
>             // DataModel as well.
>             _baseIndicesList = new IntList(sz);
>         }
>
>         final int rowIndex = _model.getRowIndex();
>
>         _model.setRowIndex(0);
>         // Make sure the model has that row 0! (It could be empty.)
>         if (_model.isRowAvailable())
>         {
>             Collections.sort(_baseIndicesList, new
> RowDataComparator(_comparator, _model));
>             _sortedIndicesList = null;
>         }
>
>         _model.setRowIndex(rowIndex);
>     }
>
>     protected class RowDataComparator implements Comparator
>     {
>                 private Comparator dataComparator = null;
>                 private DataModel dataModel = null;
>
>                 public RowDataComparator(Comparator comparator, DataModel model)
>                 {
>                         this.dataComparator = comparator;
>                         this.dataModel = model;
>                 }
>
>                 public int compare(Object arg1, Object arg2) {
>                         Integer r1 = (Integer)arg1;
>                         Integer r2 = (Integer)arg2;
>                         dataModel.setRowIndex(r1.intValue());
>                 Object rowData1 = _model.getRowData();
>                 dataModel.setRowIndex(r2.intValue());
>                 Object rowData2 = _model.getRowData();
>
>                 return dataComparator.compare(rowData1, rowData2);
>                 }
>     }
>
>
> Also, here's how I'd like to improve t:selectItems.  I've had a custom
> subclass of f:selectItems of this working for awhile.  Notice how we
> can reuse the same propertyComparator component.  This particular
> implementation can take a list of comparator children and implicitly
> wraps them in a MultipleComparator.   That's not really possible with
> a dataTable facet, so we'd want to provide a MultipleComparator
> component.
>
> <my:orderedSelectItems value="#{bean.carList}">
>     <my:propertyComparator
>          property="style.color"
>          descending="false" />
> </my:orderedSelectItems>
>