The diary of a dedicated Ubuntu user that lucked into his dream job working on the Ubuntu team.

Wednesday, December 9, 2009

More Quidgets ... No More TreeViews

TreeViews (Not Easy and Fun)If you have data that you want to display in a grid format in PyGtk is code intensive and inflexible. In Cognitive Dimensions speak we would say that the Work Step Units are too small, and the resulting code has high viscosity. It's also quite hard to learn.

In order to take a dictionary of data and display it to a user in a grid in PyGtk, you use a combination of three object:

TreeView

ListModel

TreeViewColumn

Here's some real code that I wrote while back for using the FogBugz XML API:

total_time = Nonefor interval in data:b = pyFogbugz.getbugs(session, [interval["case"]])[0]store.append([interval["start"],interval["end"],interval["duration"],interval["case"],b["title"],b["category"]])#see if this is the earliest date

#loop through and removeiters = [model.get_iter(path) for path in rows]for i in iters: self.get_model().remove(i)

#select a row for the user, nicer that wayrows_remaining = len(self.get_model())

#don't try to select anything if there are no rows leftif rows_remaining < 1: return

#select the next row down, unless it's out of range#in which case just select the last rowif next_to_select < rows_remaining: self.get_selection().select_path(next_to_select)else: self.get_selection().select_path(rows_remaining - 1)

Enter DictionaryGrid (Easy and Fun)Last week I found that the TreeView code that I wrote for bughugger was not flexible enough to incorporate some new features. In Karmic I wrote a TreeView wrapper for Desktop Couch called CouchGrid, so I had recent experience in how I could do this better, and I determined that this would be the last time that I write this code. Thus, the quidget DictionaryGrid was born. To use it, simply hand the DictionaryGrid a list of dictionaries to display and it will do the work for you.

produces this:You can use underscores and or the keys property to store data along with the dictionary that you don't want to display, and then retrieve the complete dictionary for the selected rows. If you've set the DictionaryGrid to be editable, the user can only edit the columns that are displayed, but all of the data that you passed along in the dictionaries is persisted. This is useful if you are persisting the data in a database or similar, and need to track something like the row id but don't want to expose it to the user. The code simply looks like this:

Finally, DictionaryGrid is just a subclass of gtk.TreeView, so you don't have to sacrifice any of the power and flexibility of TreeView.

GridFilterOne of the coolest things about TreeViews is that they support lightening fast filtering. But building filters for them is onerous. In fact, so onerous, I don't even want to discuss it in this posting, if you are interested, you can peruse the documentation.

However, I have created a Quidget that makes it very easy to create a filter. To cut to the chase, this code:

produces something the user can use the filters like this:Note that:1. There are built in filters for strings, numbers, and tags2. a column with a key of "Id" (case insensitive) will default to using a number filter, a column with a key of "tags" (case insentitive) will default to using a tag filter, other columns will default to a string filter3. You can create custom filters, but I don't have a base class yet to make this easy, but the code is simple if you look at GridFilter.py. In fact, the tags filter was originally written by Loic Miner.

You can override the default filter by passing in a filter hint, like this: