воскресенье, 28 сентября 2008 г.

Adding custom styles to odd/even rows in a GWT table

For the sake of better UI we decided to implement a table like gmail one that has differnt colors for even/odd rows. This seems to be quite a simple task, but I had to try several approaches before I managed to implement it.

1. Use custom RowFormatter 
RowFormatter interface defines a getElement method which is supposed to be called for every row. I believed that if you override it you can attach special style to a row object based on it's number.
Wrong guess =)
The specific table implementation - FixedWidthGrid - I was using from the gwt incubator project is using some custom/native logic inside prepareCell method so it doesn't call the getElement method =(

2. Directly override prepareCell method - doesn't seem correct, cuz would be called much more often then you need it

3. Finally I got the idea that I'm not able to find any OO way of introducing this functionality and went with a brute force approach: implement a method that applies some special formatting to all the rows and call it every time the table content is updated. 

Now I faced a new problem: there is no explicit "onContentUpdate" callback method I could use.
The only way my application now allows the content to be updated is by sorting it, so I implemented an appropriate callback. Here is the final source code packed into a class:
    public static class StripedTable extends FixedWidthGrid {
private static final String EVEN_STYLE = "even_row";
private static final String ODD_STYLE = "odd_row";

public StripedTable() {
super();
addSortableColumnsListener(new SortableColumnsListener() {
public void onColumnSorted(TableModel.ColumnSortList sortList) {
applyStripes();
}
});
}

public StripedTable(int rows, int columns) {
this();
resize(rows, columns);
}

private void applyStripes() {
for (int i = 0; i < getRowCount(); i++) {
this.getRowFormatter().setStyleName(i, getRowStyle(i));
}
}

private static String getRowStyle(int row) {
return row % 2 == 0 ? EVEN_STYLE : ODD_STYLE;
}
}

hibernate4gwt and processing all class fields

Today I was stuck working on my project which employed both hibernate and GWT technologies and thus also needed to use hibernate4gwt lib.

This is a great library that makes it possible to integrate two other great framewroks into one project. But as usual it has some caveats =)

It worked great for my model classes passing them from server side to JS client side. With one exception. All model object's ids were dropped. At first I thought this might have to do with @Id or @GeneratedValue annotations ... but that even sounds silly - why would you expect a cloning lib to drop a plain simple Long value because it has an @Id annotation? =)

Half an hour and 15Mb source code downloads later I found out the real cause. The library that hibernate4gwt uses for actual cloning of hibernate-enchanced objects to POJO is called beanlib (specifically beanlib-hibernate) and deep inside, in a method called net.sf.beanlib.provider.BeanPopulator#populate it uses all defined setters on a given class to populate it. Apparently I haven't defined a setter for id field - which caused the beanutil lib to drop it when converting to POJO.

So the moral of this story is: always create both getters and setters for all you fields on a class that you expect to pass to some 3rd party bean handling libs =)