简体   繁体   中英

Overriding Tapestry's Grid column sorting behvior

I have a page that uses a Grid table where one or more columns can be sorted. The problem is, tapestry seems to sort by the ASCII values meaning that AZ comes before az. I would like it to be sorted so that A and a come before Z and z, or true alphabetical rather than ASCII alphabetical.

I can properly sort the values during the setupRender phase, but the problem is the user can click the sort icon in the column header at any time, and the way the column will be sorted will revert to the ASCII way.

I looked at the documentation for Grid, GridSortModel, and ColumnSort and found nothing useful for overriding this behavior. I'm extremely new to tapestry, but the documentation was no help so far and I couldn't find another question that answered this online.

The version of tapestry I'm using is 5.3.6 I think.

Thank you.

edit: Here's some more context. The grid is defined in the .tml file like this:

<table t:type="grid" t:id="productGrid"
model="productModel" source="products" row="product"
                class="product-grid" inPlace="true"
                pagerPosition="both" style="width: 90%"
                include="name,processors,actions" >

Then the list of products is defined in the java file as such:

@Inject
private IProductConfigurationService _productService;
@Persist
private Set<IProductConfiguration> _products;
. . . .
_products = _productService.getProductConfigurations();

By modifying _products, then, I can modify the order of the table/grid.

Okay, I figured it out eventually. Tapestry is still a bit of a mystery to me, but someone IRL gave me a hand:

You have to replace the default GridDataSource class with your own. Note, this code can probably be refactored, but the code I use for now looks like this:

public class MyGridDataSource implements GridDataSource {
    private final List list;

    public MyGridDataSource(final Collection collection) {
        assert collection != null;
        list = CollectionFactory.newList(collection);
    }

    public int getAvailableRows() {
        return list.size();
    }

    public void prepare(int startIndex, int endIndex, List<SortConstraint> sortConstraints) {
        for (SortConstraint constraint : sortConstraints) {
            final ColumnSort sort = constraint.getColumnSort();
            if (sort == ColumnSort.UNSORTED) {
                continue;
            }

            final PropertyConduit conduit = constraint.getPropertyModel().getConduit();

            final Comparator valueComparator = new Comparator<Comparable>() {
                public int compare(Comparable o1, Comparable o2) {
                    if (o1 == null) {
                        return 1;
                    }

                    if (o2 == null) {
                        return -1;
                    }

                    String name1 = (String) o1;
                    String name2 = (String) o2;

                    for (int i = 0; i < Math.min(name1.length(), name2.length()); i++) {
                        Character c1 = name1.charAt(i);
                        Character c2 = name2.charAt(i);
                        Character C1 = Character.toUpperCase(c1);
                        Character C2 = Character.toUpperCase(c2);
                        int diff = 0;

                        // if the letters are different and different case, then....
                        // this allows "a" to come before "Z" for instance
                        if (c1.compareTo(c2) != 0 && C1.compareTo(C2) != 0 && 
                                c1.compareTo(c2) != C1.compareTo(C2)) {
                            diff = C1.compareTo(C2);
                        } else {
                            diff = c1.compareTo(c2);
                        }

                        if (diff != 0) {
                            return diff;
                        }
                    }

                    // shorter strings come first
                    return name1.length() - name2.length();
                }
            };

            final Comparator rowComparator = new Comparator() {
                public int compare(Object row1, Object row2) {
                    Comparable value1 = (Comparable) conduit.get(row1);
                    Comparable value2 = (Comparable) conduit.get(row2);

                    return valueComparator.compare(value1, value2);
                }
            };

            final Comparator reverseComparator = new Comparator() {
                public int compare(Object o1, Object o2) {
                    int modifier = sort == ColumnSort.ASCENDING ? 1 : -1;
                    return modifier * rowComparator.compare(o1, o2);
                }
            };

            Collections.sort(list, reverseComparator);
        }
    }

    public Class getRowType() {
        return list.isEmpty() ? null : list.get(0).getClass();
    }

    public Object getRowValue(int index) {
        return list.get(index);
    }

    public List getList() {
        return list;
    }
}

Okay, so then you just use this class as the type for your data. (Apparently tapestry automatically wraps your grid data with the DefaultGridDataSource if you don't specify one).

That means the above code simply changes to:

@Inject
private IProductConfigurationService _productService;
@Persist
private MyGridDataSource _products;
. . . .
_products = new MyGridDataSource(productService.getProductConfigurations());

And that's one way to override the default sorting behavior. Probably should have been easier than that. But it works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM