Saturday, April 10, 2010

Today's Slip Cover Feature(s): Deleting Keys, Refresh Button

Because I added "Add Key" yesterday, today I wanted to be symmetrical, so I added "delete keys". This turned out to be much more work. First, I ended up creating another quickly.prompt, and then I had to dive into the internals of CouchGrid, and also do some hair raising mucking with desktop couch.

When the developer clicks the "delete keys" button, I wanted to present them with a list of keys they could choose from. And then have all of those get deleted. This seemed like the kind of thing that I'd want to use in other programs, so I decided to solve this problem generically by adding it to quickly.prompts.

I accomplished this by deriving from quickly.prompts.Prompt, and also creating a helper function. CheckListPrompt works as you would expect for prompt. You set it up by passing in some configuration info, including a dictionary of strings as keys, which will be labels for the checkboxes, and a bool value to determine if the box is checked by default.

You get back a response and val. The val is a dictionary of keys again, with bools for whether the checkboxes are active or not.

So to use the CheckListBox, I just pass in a dictionary of the keys for the CouchGrid, and then see if any were selecct:
       val = {}
for k in self.grid.keys:
val[k] = False
response, val = checklist(title, message, val)
if response == gtk.RESPONSE_OK:
#do stuff

Hair Raising Munging
Since "do stuff" is pretty destructive, I use a quickly.prompts.yes_no to confirm that the users wants to blow away all the data and screw up their database. Assuming they do want to delete the keys and values in the desktopcouch database, it turns out to be *not* easy to do the deletion without reading way into CouchGrid. The issue here is the couchdb reserves anything staring with a "_" for itself. But DictionaryGrid uses "__" as a convention to determine that a key should be hidden in the grid by default. So as a result of this CouchGrid munges _id and _rev and record_type before it reads to and from the database.

The second troublesome part was dealing with desktopcouch. It turns out that you can't just delete a key from a record. You have a delete the whole record and then create a new record without that key. so as a result the code deletes and recreates each and every row.

I really think this code belongs inside CouchGrid:
    def delete_keys_from_store(self, model, path, iter, keys_to_delete):
for k in keys_to_delete:
d = model.get_value(iter,len(self.grid.keys))
if k in d:
if '__desktopcouch_id' in d:
keys = d.keys()
for k in keys:
if k.startswith("__desktopcouch"):
dc_key = k.split("__desktopcouch")[1]
d[dc_key] = d[k]
if k == "__record_type":
d["record_type"] = d["__record_type"]

Who would ever be able to figure out to do all this?

So after this the refresh function was trivial. Just tell the CouchGrid to reset, and then recreate the grid:
    def refresh(self, widget, data=None):
self.filt = GridFilter(self.grid)
self.pack_start(self.filt, False, False)

desktopcouch Editor
So now with adding a removing records and keys, along with freshing, I have a functional desktopcouch editor. This tool has already proved a bit useful in getting a peak into certain database. However, I can't actually create new record types yet. Maybe tomorrow?


  1. Heh, I was trying to do this exact thing (deleting records with a UI) this weekend. Do you think it would be useful to include such convenience function in quickly-widgets?

  2. @LaserJock:

    I logged a few bugs to move some functions into CouchGrid:

    Cheers, Rick