I am writing a user interface for data-entry. Because data-entry sucks I am trying to make this UI as usable as possible. This includes accelerator values for each field. For example, a field to enter a car name will include buttons for each of the most popular values for that field. Clicking on such a button will populate the car name with the corresponding value:
The list of suggested values is sorted by popularity. The value that has been entered the most times is the first suggestion, and the second most popular entry is second, etc.
Now the fun part is implementing it. Traditionally this would be done with a SQL query with some GROUP BY, ORDER BY and COUNT parameters. Unfortunately I am limiting myself to EJB-QL, which is not (yet) powerful enough to do this.
This got me thinking, could I implement this using Glazed Lists? I want to take an arbitrary EventList and return a second EventList of those values, sorted by popularity.
Since UniqueList has a method to get the count of duplicates for a given value, this is possible. I simply sort the UniqueList by this duplicates count. There's still one major difficulty: UniqueList doesn't currently fire events on that duplicate count changing. But a solution is definitely possible.
I have a program that generates an Excel file that can contain hundreds of sheets. To make this more manageable, the first sheet is an 'index' sheet that summarizes the sheets to follow. Each row in this index is hyperlinked to the a sheet that provides further detail.
Here's some tips on creating Hyperlinks in Excel .xls documents using Jakarta POI:
Excel hyperlinks are formulas with this syntax: HYPERLINK( "target", "label")
To link to the first cell in a sheet called sheetname, use "#sheetname!A1"
Sheet names in Excel can contain spaces and commas, but you cannot link to such sheets. I recommend sticking to letters, numbers and underscore for best results. Sheet names must also be 31 characters or less. That's 2^5-1.
Data objects are the new orange! So I am continuously coding data objects and I find myself writing a lot of repetitive comparison code:
public int compareTo(Object other) {
if(other == null) return -1;
Car otherCar = (Car)other;
So now I have a new class called Comparators. It has a handy method that gets a custom comparator, given a handful of properties to test in sequence:
private static String[] compareProperties = new String[] { "color", "speed", "year" };
private static Comparator comparator = Comparator.properties(Car.class, compareProperties };
public int compareTo(Object other) {
return comparator.compare(this, other);
}
Reflection and JavaBeans are great! Now all I need to do is extend this so that it also works with equals() and hashCode().
Originally, the Glazed Lists demo app would parse a file called "issues.xml" each time it was run. I got "issues.xml" by exporting my Issuezilla database from java.net. This worked okay, but the exported XML included everything in the database including attachments. Of course I did not want to include all of this in the download for the demo app.
About six months ago, I exported the xml file from the database and manually removed the attachments with jEdit and grep. This process was labour intensive and yielded only marginal success.
Recently I decided issues.xml file was out-of-date and I needed to bring it up to date. I did not want to fix it manually again.
Conventional thinking would have me create an XSLT transformation or a utility application that took in XML and wrote out trimmed XML. But that strategy is lame.
Instead, I took the parser for the issues.xml file that I already had. This parser read in the issues.xml file to produce an ArrayList of Issue objects. I modified this program so that whenever it modified an Issue object, it System.out.println'd the code that did that:
public void addFieldAndValue(String currentField, String value) {
if(currentField.equals("issue_id")) {
currentIssue.setId(Integer.valueOf(value));
System.out.println("currentIssue.setId(Integer.valueOf(" + value + "));");
}
...
}
So now my XML parser outputs Java code. I simply compiled this code and now I have a program that produces an ArrayList of issues. But it does no parsing -- it just constructs the issues and returns.
There was a recent bug in Glazed Lists that was difficult to plan for. Consider this:
- "S", a source list
- "F1", a filtered transformation of "S"
- "F2", a filtered transformation of "S"
- "FF", a filtered transformation of "F1" that also depends on "F2"
When "S" changes, an event is sent to "F1", which in turn forwards the event to "FF". This returns and then "S" sends the event to "F2". But when "FF" is notified, it inspects "F2", which has not yet received the event from "S". This causes "F2" to be in an inconsistent state, and erratic behaviour ensues. In this case an ArrayIndexOutOfBounds exception was being thrown.
The problem was that although "S" was up-to-date, "FF" was looking at "F2", which was not yet up to date.
The end solution involves explicitly managing the dependencies of each ListEventListener. Now "S" fires an event to "F1", but "F1" does NOT forward it to "FF". Instead, "F1" returns and "S" proceeds to forward the event to "F2". Finally the event is forwarded as if it came from "F1".
Today I tried for a few hours to get Xandros to burn some DVDs on my new burner. It was grumpy so after two DVD-coasters I threw in the towel and installed Windows XP. It's a decent alternative to Linux but it has a crappy shell and its SMB client sucks.
While I was waiting I drew up some pretty sort-arrow indicator icons for Glazed Lists. Look at the screenshots to see my handywork. I've wasted a lot of time on drawing icons for all the various look & feels, but the result looks professional.
In my comparison I have analyzed how JDNC did their JTableHeader. They've done a lot of work on adding anti-aliasing, plus their right-aligned icons look great. Unfortunately they also blew away the platform-specific header backgrounds! This is particularly obvious in the XP theme. Hopefully Sun can talk to Sun and they can get that straightened out.
Finally I must complain that Swing's UIManager doesn't let you know which look and feel you're using. Try to differentiate between old-skool metal and ocean, or grey-and-grey Windows 95 and lickable Luna in code. It's hard. I've written code that does that and now I wonder if I should make it available online or something.