Lead, Anchor and a new ListSelectionModel bug

Today I discovered a new bug in Glazed Lists' EventSelectionModel. That class implements ListSelectionModel, which a JTable uses to manage the current selection. One of these duties is to manage the lead and anchor indices, which are used for dragging a selection with the mouse. Where the mouse started the drag is the anchor, where it is currently is the lead. Everything between them shall become selected! Now this all broke down in a fairly simple case. If the user selects an anchor and then filters the list, the EventSelectionModel kept that same old anchor index - even if the list shrank so much that the anchor index was out of range. When the user would select a new lead (via shift-click), the incorrect anchor was called upon and an IndexOutOfBoundsException was thrown. This is all fixed now, but it was quite a nasty little bug, and it had been in the code for a long long time.

It makes me wonder:
  • Had anyone else ever seen this behaviour? It had never been reported.
  • How many more bugs are in the code?

    I'm fairly confident with our code, but it irks me to see that such an obvious bug had stayed hidden so long!
  • A super() Java Language Hack

    I'm creating an EventList called PopularityList that will sort elements by the number of times they occur in the source EventList. I'm extending TransformedList, which has a single protected constructor with the signature:
    protected TransformedList(EventList source);

    To implement PopularityList:
  • First I create a UniqueList of the source EventList's elements.
  • Wrap that UniqueList in a SortedList, sorting by the number of duplicates in the UniqueList

    But when I combined these two problems in the most natural way, I had a problem:
    private UniqueList ul = null;

    public PopularityList(EventList source) {
    super(new SortedList(new UniqueList(source), new PopularityComparator());

    The problem is that my PopularityList class needs to keep a reference to the UniqueList object created in the constructor. But the two obvious attempts fail to compile. The first solution fails due to "cannot reference ul before supertype constructor has been called":
    private UniqueList ul = null;

    public PopularityList(EventList source) {
    super(new SortedList(ul = new UniqueList(source), new PopularityComparator());

    The second solution is a very slight variation that fails due to "')' expected":
    private UniqueList ul = null;

    public PopularityList(EventList source) {
    super(new SortedList(UniqueList temp = new UniqueList(source), new PopularityComparator());
    ul = temp;

    So what did I do next? I paniced! But that got boring so I came up with a clever hack. I created a private constructor that has a parameter for each object that I need to keep a reference to, then I called this(). It works perfectly:
    private UniqueList ul = null;

    public PopularityList(EventList source) {
    this(source, new UniqueList(source));
    private PopularityList(EventList source, UniqueList uniqueList) {
    super(new SortedList(uniqueList, new PopularityComparator()));
    this.ul = uniqueList;
  • One Page Whitepaper

    I've created a really quick PDF that gives a fast overview of how sorting is implemented in Glazed Lists. I needed to write such a paper for some accounting stuff at work, but it's fun to post online.

    The only problem is that now JDNC and everyone else can learn our secret to sorting performance! But for the time being I don't think that they are interested in our performance advice.

    POI, hyperlinks, and 2^7

    As I mentioned earlier, I am using Jakarta POI to create Excel files.

    Earlier I warned:
  • don't use space characters (or commas or pretty much anything else)
  • limit sheet names to 31 characters

    Well today I discovered another unpleasant limitation. The link label must be 127 characters or fewer. If not, POI may throw an exception or create an unreadable file.

    I get the feeling that the formula support in POI is still fresh. Hopefully these limitations won't be permanent!
  • IOException "The handle is invalid"

    The pure Java version of our program was working flawlessly. The GCJ-compiled Windows binary was not. It was throwing an IOException, "The handle is invalid". This is caused because InputStream.close() was being called multiple times. By removing a close() call, everything now works correctly.

    This raises an important question: who's job is it to close an input stream? For example:
    InputStream in = ...
    BufferedInputStream bufferedIn = new BufferedInputStream(in);

    Do I still need to call in.close()?

    According to the API, I should not call in.close() because BufferedInputStream.close() does that for me.

    Filter Faster

    The filter classes in Glazed Lists have received a shitload of attention lately.

    First, James Lemieux implemented Boyer-Moore in our TextFilterList class. His efforts led to a 20-50% performance boost. James is currently working on refactoring the TextFilterList and AbstractFilterList classes which may lead to further performance increases.

    Now today Kevin finished the first phase of our new data structure which manages filtering. In a test program with 2,500 list elements, filtering was 10% faster. With 250,000 elements, filtering was twice as fast!

    This is a very exciting time for Glazed Lists. In the last two weeks there has been more code written by Kevin and James than I have written myself. This is the very good because both guys have written really high quality stuff that simplifies Glazed Lists rather than introducing complexity.

    SWT Frustration of the day: Constants

    The SWT GridData class has 25 public static final int constants, including the following:
  • END

    GridData also has a constructor:
    public GridData(int horizontalAlignment, int verticalAlignment, boolean grabExcessHorizontalSpace, boolean grabExcessVerticalSpace)

    Which 3 of the above constants are accepted values for the horizontalAlignment argument in this constructor?

    If you guessed HORIZONTAL_ALIGN_BEGINNING, HORIZONTAL_ALIGN_CENTER, and HORIZONTAL_ALIGN_END, you're wrong. The constructor only understands BEGINNING, CENTER, and END.