
I mentioned in a previous post that I was finding PyTask to be pretty cool. Of course, one of the cool things, for me, was that it used Quickly Widgets. As I mentioned, Quickly Widgets lacked some key features, like a DateColumn.
Having a user means that I know at least one way that someone it trying to use the code. I went ahead and implemented a DateColumn in PyTask, and my next step will be to add DateColumn to quickly widgets, so Ryan doesn't have to maintain the code in PyTask. First I need to kind of make room for this in the grid_filter module. I have a good idea of how to do it, so just a SMOP at this point.
There were other more subtle things that I ran into as well. For example, it turns out that I didn't handle the case of deleting rows in a CouchGrid, or even removing rows from a DictionaryGrid if that grid was filtered. The later case was "just" a bug. So I worked around this in PyTask code so that PyTask could ship while waiting for me to fix Quickly Widgets.
Since I have intimate knowledge about how the PyGtk was assembled, I was able to write this code for PyTask
    def remove_row(self, widget, data=None):
"""Removes the currently selected row from the couchgrid."""
# work around to actually delete records from desktopcouch
# in maverick, using delete=true in remove_selected_rows will have
# the same effect
database = CouchDatabase("pytask")
for r in self.grid.selected_rows:
   database.delete_record(r["__desktopcouch_id"])
if type(self.grid.get_model()) is gtk.ListStore:
   self.grid.remove_selected_rows()
else:
   # The following code works around:
   # https://bugs.edge.launchpad.net/quidgets/+bug/587568
   # get the selected rows, and return if nothing is selected
   model, rows = self.grid.get_selection().get_selected_rows()
   if len(rows) == 0:
       return
   # store the last selected row to reselect after removal
   next_to_select = rows[-1][0] + 1 - len(rows)
   # loop through and remove
   iters = [model.get_model().get_iter(path) for path in rows]
   store_iters = []
   for i in iters:
       # convert the iter to a useful iter
       store_iters.append(model.get_model().convert_iter_to_child_iter(i))
   for store_iter in store_iters:
       # remove the row from the store
       self.filt.store.remove(store_iter)
   # select a row for the user, nicer that way
   rows_remaining = len(model)
   # don't try to select anything if there are no rows left
   if rows_remaining < 1:
       return
   # select the next row down, unless it's out of range
   # in which case just select the last row
   if next_to_select < rows_remaining:
       self.grid.get_selection().select_path(next_to_select)
   else:
       self.grid.get_selection().select_path(rows_remaining - 1)
So I moved the code to delete records from desktop couch into CouchGrid.remove_selected_rows and all the "remove properly even if filtered" goo into DictionaryGrid.remove_selected_rows. The result is that when the next version of Quickly Widgets lands, Ryan will be able to simplify the function down to this:
    def remove_row(self, widget, data=None):
"""Removes the currently selected row from the couchgrid."""
self.grid.remove_selected_rows(delete=True)
Another area where the DictionaryGrid lacked functionality was related to column titles. It was easy to write a little code to change the column titles:
        for c in self.grid.get_columns():
      if c.get_title() == "name":
          c.set_title(_("Name"))
      elif c.get_title() == "priority":
          c.set_title(_("Priority"))
      elif c.get_title() == "due":
          c.set_title(_("Due"))
      elif c.get_title() == "project":
          c.set_title(_("Project"))
      if c.get_title() == "complete?":
          c.set_title(_("Completed"))
Again, knowing the structure of the PyGtk intimately, I was able to work around this by modifying rows in the filter as each is created:
   def __new_filter_row(self, widget, data=None):
   """
   new_filter row - hack to allow naming of columns
   in a grid filter.
   This code works around:
   https://bugs.edge.launchpad.net/quidgets/+bug/587558
   """
   row = self.filt.rows[len(self.filt.rows)-1]
   row.connect("add_row_requested",self.__new_filter_row)
   model = row.column_combo.get_model()
   for i, k in enumerate(model):
       itr = model.get_iter(i)
       title = model.get_value(itr,0)
       if title == "name":
           model.set_value(itr,0,_("Name"))
       elif title == "priority":
           model.set_value(itr,0,_("Priority"))
       elif title == "due":
           model.set_value(itr,0,_("Due"))
       elif title == "project":
           model.set_value(itr,0,_("Project"))
       if title == "complete?":
           model.set_value(itr,0,_("Completed"))
I fixed this a bit easier in Quickly Widgets.
        grid.columns["key1_1"].set_title("KEY")
I also made a convenience function that Ryan can use. Here's the code from the tests:
        titles = {"key1_1":"KEY1","key1_2":"KEY2","key1_3":"KEY3"}
     grid.set_column_titles(titles)
Anyway, thanks to Ryan for letting me use PyTask to improve Quickly Widgets!
No comments:
Post a Comment