[ 
https://issues.apache.org/jira/browse/TOMAHAWK-952?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12485543
 ] 

Mike Kienenberger commented on TOMAHAWK-952:
--------------------------------------------

As a first step in this process, I've separated SortableDataModel into 
SortableDataModel (current behavior, final, subclass of BaseSortableDataModel) 
and BaseSortableDataModel (extendable, works with Comparators).

> Provide cleaner, consistent sorting for dataTable and selectItems
> -----------------------------------------------------------------
>
>                 Key: TOMAHAWK-952
>                 URL: https://issues.apache.org/jira/browse/TOMAHAWK-952
>             Project: MyFaces Tomahawk
>          Issue Type: New Feature
>          Components: Extended Datatable, Extended SelectItems, New Component
>    Affects Versions: 1.1.6-SNAPSHOT
>            Reporter: Mike Kienenberger
>         Assigned To: Mike Kienenberger
>            Priority: Minor
>
> My requirements in most cases are to 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>

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to