覆盖 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());
这是覆盖默认排序行为的一种方法。可能应该比那更容易。但它有效。
我有一个使用网格 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());
这是覆盖默认排序行为的一种方法。可能应该比那更容易。但它有效。