Wednesday, December 23, 2009

Curse you TreeView, why must you break my heart so?

I've continued to make good progress on DictionaryGrid, and feel that I am close to having a fun and easy replacement for TreeView programming. However, once again I was stunned by the incredible viscosity of the TreeView API, not to mention the unexpected behaviors.

Curse you TreeView API!!

What's the difference between to the two highlighted zeros in the ID column above? The first one was passed into the DictionaryGrid by the test program, but the second was a default value added by, I suppose, the ListStore as a default value. I think this happened because I changed the type of that column to gobject.TYPE_INT to support proper sorting. However, I can't pass in an empty string or None, as ListStore will not accept a value that is not an integer. If I append an empty row, missing numbers get initialized as zero.

Now, there is a big difference between a value in a grid being zero because it's set to zero, and being zero because that's the default. So these columns have to support empty cells.

I believe I can achieve this by making all of the numeric columns of type gobject.TYPE_STRING, but then overriding the sorting method to be numerical (hopefully without adding some kind of hideously slow bubble sort or something ;) ).

Yesterday I was doing a lot of detecting types to specialize behaviors. This is a classic sign of needing to do a refactor into subclasses. So I spent yesterday subclassing TreeViewColumn to support Integers, Strings, Currency, and Booleans the way I wanted. Having these subclasses already in place, I think I can add the numeric sorting in a relatively straight forward manner.

The good news is that the code to create a dictionary view still has not changed, yet Integer, Currency, String, and Boolean columns are all created automagically, and the consuming code has not changed. Here is the code to create the DictionaryGrid pictured above:
   dicts = [{"key?": True, "price":0.00,"tags" : "aaa bbb ccc","_foo":"bar"},
{"ID": 1, "key?": False, "price":2.00,"tags" : "bbb ccc ddd","_foo":"bar"},
{"key?": True, "price":3.00,"tags" : "ccc ddd eee","_foo":"bar"},
{"ID": 3, "key?": False, "price":4.00,"tags" : "ddd eee fff","_foo":"bar"},
{"ID": 4, "key?": True, "price":5.00,"tags" : "eee fff ggg","_foo":"bar"}]

grid = DictionaryGrid(dicts, ["ID","tags","price","key?"])
grid.editable = False


  1. To be honest, I'd say that this sort of API design is a good thing. If I say that a column contains integers, then I want to know that I'm only ever going to read integers out of it.

    It also isn't obvious to me if the correct sort behavior is [Missing, 1, 2] or [1, 2, Missing]. I can imagine situations where both of these are correct. If the API doesn't know, it shouldn't guess (in my opinion).