覆盖 Tapestry 网格列排序行为

Overriding Tapestry's Grid column sorting behvior

我有一个使用网格 table 的页面,其中可以对一个或多个列进行排序。问题是,Tapestry 似乎按 ASCII 值排序,这意味着 A-Z 在 a-z 之前。我希望对它进行排序,以便 A 和 a 在 Z 和 z 之前出现,或者是真正的字母顺序而不是 ASCII 字母顺序。

我可以在 setupRender 阶段对值进行正确排序,但问题是用户可以随时单击列 header 中的排序图标,并且列的排序方式将恢复为ASCII 方式。

我查看了 Grid、GridSortModel 和 ColumnSort 的文档,但没有发现对覆盖此行为有用的内容。我对挂毯非常陌生,但到目前为止文档没有帮助,我找不到另一个在线回答这个问题的问题。

我用的tapestry版本好像是5.3.6。

谢谢。

编辑:这里有更多背景信息。网格在 .tml 文件中定义如下:

<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" >

然后产品列表在 java 文件中定义如下:

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

通过修改_products的话,我可以修改table/grid的顺序。

好吧,我终于明白了。 Tapestry 对我来说还是有点神秘,但是有人 IRL 帮了我一把:

您必须将默认的 GridDataSource class 替换为您自己的。请注意,此代码可能会被重构,但我现在使用的代码如下所示:

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;
    }
}

好的,那么您只需使用此 class 作为您的数据类型。 (显然,如果您不指定 DefaultGridDataSource,挂毯会自动使用 DefaultGridDataSource 包装您的网格数据)。

这意味着上面的代码只需更改为:

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

这是覆盖默认排序行为的一种方法。可能应该比那更容易。但它有效。