Adjusting combo boxes / spiners
[multilist] / src / libview.py
index 9a08869..4f568e4 100644 (file)
@@ -20,13 +20,16 @@ along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
 Copyright (C) 2008 Christoph Würstle
 """
 
+import sys
 import logging
 
-import gtk
 import gobject
+import gtk
 import pango
 
+import hildonize
 import gtk_toolbox
+import libliststorehandler
 
 
 try:
@@ -38,10 +41,10 @@ except NameError:
 _moduleLogger = logging.getLogger(__name__)
 
 
-class CellRendererTriple(gtk.GenericCellRenderer):
+class TripleToggleCellRenderer(gtk.CellRendererToggle):
+
        __gproperties__ = {
-               "status": (gobject.TYPE_STRING, "Status",
-               "Status", "", gobject.PARAM_READWRITE),
+               "status": (gobject.TYPE_STRING, "Status", "Status", "", gobject.PARAM_READWRITE),
        }
 
        __gsignals__ = {
@@ -49,202 +52,86 @@ class CellRendererTriple(gtk.GenericCellRenderer):
        }
 
        def __init__(self):
-               #self.__gobject_init__()
-               #gtk.GenericCellRenderer.__init__(self, *args, **kwargs)
-               gtk.GenericCellRenderer.__init__(self)
-               #self.__gobject_init__()
-               self.status = -1
-               self.xpad = 2
-               self.ypad = 2
-               self.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
-               self.xpad = -2
-               self.ypad = -2
-               self.xalign = 0.5
-               self.yalign = 0.5
-               self.active = 0
-               self.widget = None
-               self.last_cell = None
-               self.connect('editing-started', self.on_clicked)
+               gtk.CellRendererToggle.__init__(self)
+               self.set_property("activatable", True)
+               self.connect('toggled', self._on_toggled)
+               self.status = libliststorehandler.Liststorehandler.SHOW_NEW
 
+       @gtk_toolbox.log_exception(_moduleLogger)
        def do_set_property(self, property, value):
-               setattr(self, property.name, value)
-
-       def do_get_property(self, property):
-               return getattr(self, property.name)
-
-       def get_layout(self, widget):
-               '''Gets the Pango layout used in the cell in a TreeView widget.'''
-
-               layout = pango.Layout(widget.get_pango_context())
-               layout.set_width(-1)    # Do not wrap text.
-
-               layout.set_text('  ')
-
-               return layout
-
-       def on_get_size(self, widget, cell_area = None):
-               xpad = 2
-               ypad = 2
-
-               xalign = 0
-               yalign = 0.5
-
-               layout = self.get_layout(widget)
-               width, height = layout.get_pixel_size()
-
-               x_offset = xpad
-               y_offset = ypad
-
-               if cell_area:
-
-                       x_offset = xalign * (cell_area.width - width)
-                       x_offset = max(x_offset, xpad)
-                       x_offset = int(round(x_offset, 0))
-
-                       y_offset = yalign * (cell_area.height - height)
-                       y_offset = max(y_offset, ypad)
-                       y_offset = int(round(y_offset, 0))
-
-               width  = width  + (xpad * 2)
-               height = height + (ypad * 2)
-
-               return x_offset, y_offset, width, height
-
-       def on_clicked(self,  widget, data):
-               print widget, data
-
-       def clicked(self, widget, data1 = None):
-               x, y = widget.get_pointer()
-               widget.realize()
-
-               path = widget.get_path_at_pos(x, y)
-
-               #print "a", widget.get_cursor()
-               #print path
-
-               path = widget.get_cursor()[0]
-
-               if path is not None:
-                       irow = path[0]  #path[0][0]-1
-                       rect = widget.get_cell_area(irow, widget.get_column(0)) #FixME 0 is hardcoded
-                       if x < rect.x+rect.width:
-                               self.emit("status_changed", irow, self.status)
-               else:
+               if getattr(self, property.name) == value or value is None:
                        return
 
-                       #workarround -1 means last item, because bug in treeview?!
-                       #print "not in list"
-                       rect = widget.get_visible_rect() #widget.get_cell_area(-1, widget.get_column(0))
-                       #print rect.x, rect.y, rect.width, rect.height, x, y
-                       irow = -1
-                       rect = widget.get_cell_area(0, widget.get_column(0)) #FixME 0 is hardcoded
-                       if x < rect.x+rect.width:
-                               self.emit("status_changed", irow, "-1")
-
-       def on_render(self, window, widget, background_area, cell_area, expose_area, flags ):
-               if (self.widget == None):
-                       #print widget
-                       self.widget = widget
-                       self.widget.connect("cursor-changed", self.clicked) #button-press-event
-
-               self.last_cell = cell_area
-
-               x = int(cell_area.x+(cell_area.width-2)/2-(cell_area.height-2)/2)
-               y = int(cell_area.y+1)
-               height = int(cell_area.height-2)
-               width = int(height)
-
-               if (self.status == "1"):
-                       widget.style.paint_check(window, gtk.STATE_NORMAL, gtk.SHADOW_IN, cell_area, widget, "cellradio", x, y, width, height)
-               elif (self.status == "0"):
-                       #width = height
-                       height = height-3
-                       width = height
-
-                       widget.style.paint_flat_box(window, gtk.STATE_NORMAL, gtk.SHADOW_NONE, cell_area, widget, "cellunselected", x, y, width, height)
+               setattr(self, property.name, value)
 
-                       widget.style.paint_hline(window, gtk.STATE_NORMAL, cell_area, widget, "cellunselected", x, x+width, y)
-                       widget.style.paint_hline(window, gtk.STATE_NORMAL, cell_area, widget, "cellunselected", x, x+width, y+height)
-                       widget.style.paint_vline(window, gtk.STATE_NORMAL, cell_area, widget, "cellunselected", y, y+height, x)
-                       widget.style.paint_vline(window, gtk.STATE_NORMAL, cell_area, widget, "cellunselected", y, y+height, x+width)
+               if property.name == "status":
+                       active, inconsistent = {
+                               libliststorehandler.Liststorehandler.SHOW_NEW: (False, False),
+                               libliststorehandler.Liststorehandler.SHOW_ACTIVE: (False, True),
+                               libliststorehandler.Liststorehandler.SHOW_COMPLETE: (True, False),
+                       }[value]
+                       self.set_property("active", active)
+                       self.set_property("inconsistent", inconsistent)
 
-               else:
-                       widget.style.paint_diamond(window, gtk.STATE_NORMAL, gtk.SHADOW_IN, cell_area, widget, "cellunselected", x, y, width, height)
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def do_get_property(self, property):
+               return getattr(self, property.name)
 
-               #widget.show_all()
-               #print "render"
-               pass
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_toggled(self, widget, path):
+               self.emit("status_changed", int(path), "-1")
 
-       def on_start_editing(self, event, widget, path, background_area, cell_area, flags):
-               print "on_start_editing", path
-               return None
 
-       def on_activate(self, event, widget, path, background_area, cell_area, flags):
-               print "activate", path
-               return False
+gobject.type_register(TripleToggleCellRenderer)
 
 
-class CellRendererCombo2(gtk.GenericCellRenderer):
+class CellRendererTriple(gtk.GenericCellRenderer):
        __gproperties__ = {
-               "text": (gobject.TYPE_STRING, "text",
-               "Text", "", gobject.PARAM_READWRITE),
+               "status": (gobject.TYPE_STRING, "Status", "Status", "", gobject.PARAM_READWRITE),
        }
 
        __gsignals__ = {
-               'status_changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)),
+               'status_changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_INT,gobject.TYPE_STRING)),
        }
 
        def __init__(self):
-               #self.__gobject_init__()
-               #gtk.GenericCellRenderer.__init__(self, *args, **kwargs)
                gtk.GenericCellRenderer.__init__(self)
-               #self.__gobject_init__()
                self.status = -1
-               self.xpad = 2
-               self.ypad = 2
-               self.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
-               self.xpad = -2
-               self.ypad = -2
-               self.xalign = 0.5
-               self.yalign = 0.5
-               self.active = 0
-               self.widget = None
                self.last_cell = None
-               self.text = "(none)"
-               self.connect('editing-started', self.on_clicked)
 
-       def do_set_property(self, property, value):
-               #print property, value
+               self.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE)
+               self.set_property('visible', True)
+
+       def do_set_property(self,property,value):
                setattr(self, property.name, value)
 
        def do_get_property(self, property):
                return getattr(self, property.name)
 
-       def get_layout(self, widget):
+       def _get_layout(self, widget):
                '''Gets the Pango layout used in the cell in a TreeView widget.'''
 
                layout = pango.Layout(widget.get_pango_context())
-               layout.set_width(-1)    # Do not wrap text.
+               layout.set_width(-1) # Do not wrap text.
 
-               layout.set_text(self.text)
+               layout.set_text('  ')
 
                return layout
 
-       def on_get_size(self, widget, cell_area = None):
+       def on_get_size(self, widget, cell_area=None):
+               layout = self._get_layout(widget)
+               width, height = layout.get_pixel_size()
+
                xpad = 2
                ypad = 2
 
                xalign = 0
                yalign = 0.5
 
-               layout = self.get_layout(widget)
-               width, height = layout.get_pixel_size()
-
                x_offset = xpad
                y_offset = ypad
 
-               if cell_area:
-
+               if cell_area is not None:
                        x_offset = xalign * (cell_area.width - width)
                        x_offset = max(x_offset, xpad)
                        x_offset = int(round(x_offset, 0))
@@ -253,67 +140,50 @@ class CellRendererCombo2(gtk.GenericCellRenderer):
                        y_offset = max(y_offset, ypad)
                        y_offset = int(round(y_offset, 0))
 
-               width  = width  + (xpad * 2)
+               width = width + (xpad * 2)
                height = height + (ypad * 2)
 
                return x_offset, y_offset, width, height
 
-       @gtk_toolbox.log_exception(_moduleLogger)
-       def on_clicked(self,  widget, data):
-               print widget, data
-
-       def clicked(self, widget, data1 = None):
-               return
-               x, y = widget.get_pointer()
-               widget.realize()
-
-               #path = widget.get_path_at_pos(x, y)
-
-               path = widget.get_cursor()[0]
-
-               if path is not None:
-                       irow = path[0]  #path[0][0]-1
-                       rect = widget.get_cell_area(irow, widget.get_column(0)) #FixME 0 is hardcoded
-                       if x < rect.x+rect.width:
-                               self.emit("status_changed", irow, self.status)
-               else:
-                       return
-
-                       #workarround -1 means last item, because bug in treeview?!
-                       #print "not in list"
-                       rect = widget.get_visible_rect() #widget.get_cell_area(-1, widget.get_column(0))
-                       #print rect.x, rect.y, rect.width, rect.height, x, y
-                       irow = -1
-                       rect = widget.get_cell_area(0, widget.get_column(0)) #FixME 0 is hardcoded
-                       if x < rect.x+rect.width:
-                               self.emit("status_changed", irow, "-1")
-
        def on_render(self, window, widget, background_area, cell_area, expose_area, flags ):
-               if (self.widget == None):
-                       self.widget = widget
-                       self.widget.connect("cursor-changed", self.clicked) #button-press-event
-
                self.last_cell = cell_area
 
-               x = int(cell_area.x+(cell_area.width-2)/2-(cell_area.height-2)/2)
-               y = int(cell_area.y+1)
-               height = int(cell_area.height-2)
-               width = int(height)
-
-               widget.style.paint_layout(window, gtk.STATE_NORMAL, True, cell_area, widget, "cellradio", x, y, self.get_layout(widget))
-
-               #widget.show_all()
+               x = cell_area.x
+               y = cell_area.y
+               width = cell_area.width
+               height = cell_area.height
+
+               if False:
+                       # This is how it should work but due to theme issues on Maemo, it doesn't work
+                       if widget.state == gtk.STATE_INSENSITIVE:
+                               state = gtk.STATE_INSENSITIVE
+                       elif flags & gtk.CELL_RENDERER_SELECTED:
+                               if widget.is_focus():
+                                       state = gtk.STATE_SELECTED
+                               else:
+                                       state = gtk.STATE_ACTIVE
+                       else:
+                               state = gtk.STATE_NORMAL
+
+               if self.status == libliststorehandler.Liststorehandler.SHOW_COMPLETE:
+                       shadow = gtk.SHADOW_IN
+                       state = gtk.STATE_NORMAL
+               elif self.status == libliststorehandler.Liststorehandler.SHOW_ACTIVE:
+                       shadow = gtk.SHADOW_ETCHED_IN
+                       state = gtk.STATE_NORMAL
+               elif self.status == libliststorehandler.Liststorehandler.SHOW_NEW:
+                       shadow = gtk.SHADOW_OUT
+                       state = gtk.STATE_SELECTED
+               else:
+                       raise NotImplementedError(self.status)
 
-       def on_start_editing(self, event, widget, path, background_area, cell_area, flags):
-               print "on_start_editing", path
-               return None
+               widget.style.paint_check(window, state, shadow, cell_area, widget, "cellcheck",x,y,width,height)
 
        def on_activate(self, event, widget, path, background_area, cell_area, flags):
-               print "activate", path
+               self.emit("status_changed", int(path), "-1")
                return False
 
 
-gobject.type_register(CellRendererCombo2)
 gobject.type_register(CellRendererTriple)
 
 
@@ -335,34 +205,6 @@ class View(gtk.VBox):
                ls = self.liststorehandler.get_liststore()
                self.treeview.set_model(ls)
 
-       def col_edited(self, cell, irow, new_text, icol = None):
-               if (irow != 4):
-                       self.liststorehandler.update_row(irow, icol, new_text)
-               else:
-                       print cell, irow, new_text, icol
-
-       def col_toggled(self, widget, irow, status ):
-               ls = self.treeview.get_model()
-
-               if self.liststorehandler.get_filter() == self.liststorehandler.SHOW_ACTIVE:
-                       if ls[irow][1] == "0":
-                               self.liststorehandler.update_row(irow, 1, "1")
-                       else:
-                               self.liststorehandler.update_row(irow, 1, "0")
-               else:
-                       if ls[irow][1] == "1":
-                               self.liststorehandler.update_row(irow, 1, "-1")
-                       elif ls[irow][1] == "0":
-                               self.liststorehandler.update_row(irow, 1, "1")
-                       else:
-                               self.liststorehandler.update_row(irow, 1, "0")
-
-       def convert(self, s):
-               if s == "1":
-                       return 1
-               else:
-                       return 0
-
        def del_active_row(self):
                path, col = self.treeview.get_cursor()
                if path is not None:
@@ -370,9 +212,6 @@ class View(gtk.VBox):
                        row_iter = self.treeview.get_model().get_iter(path)
                        self.liststorehandler.del_row(irow, row_iter)
 
-       def sort_func_function(self, model, iter1, iter2, data = None):
-               print "sorting"
-
        def reload_view(self):
                # create the TreeView using liststore
                self.modelsort = gtk.TreeModelSort(self.liststorehandler.get_liststore())
@@ -380,6 +219,7 @@ class View(gtk.VBox):
 
                self.treeview = gtk.TreeView(self.modelsort)
                self.treeview.set_headers_visible(True)
+               self.treeview.set_reorderable(False)
 
                self.cell = range(self.liststorehandler.get_colcount())
                self.tvcolumn = range(self.liststorehandler.get_colcount())
@@ -387,41 +227,57 @@ class View(gtk.VBox):
                m = self.liststorehandler.get_unitsstore()
 
                for i in range(self.liststorehandler.get_colcount()):
-                       if i in [1, 2]:
+                       if i in [1, 2]: # status, title
                                default = "1"
                        else:
                                default = "0"
                        if self.db.ladeDirekt("showcol_"+str(self.liststorehandler.get_colname(i)), default) == "1":
-                               if i in [1]:
-                                       self.cell[i] = CellRendererTriple()
+                               if i in [1]: # status
+                                       # HACK Hildon has theme issues with inconsistent items, so
+                                       # we have a hacked together toggle to make it work on
+                                       # hildon
+                                       if hildonize.IS_HILDON_SUPPORTED:
+                                               self.cell[i] = CellRendererTriple()
+                                       else:
+                                               self.cell[i] = TripleToggleCellRenderer()
+                                       self.cell[i].connect('status_changed', self._on_col_toggled)
                                        self.tvcolumn[i] = gtk.TreeViewColumn("", self.cell[i])
-                                       self.cell[i].connect( 'status_changed', self.col_toggled)
                                        self.tvcolumn[i].set_attributes( self.cell[i], status = i)
-                               elif i in [3, 6]:
+                               elif i in [3, 5]: # quantity, price
+                                       self.cell[i] = gtk.CellRendererSpin()
+                                       adjustment = gtk.Adjustment(0, -sys.float_info.max, sys.float_info.max, 1)
+                                       self.cell[i].set_property('adjustment', adjustment)
+                                       self.cell[i].set_property('digits', 2 if i == 5 else 0)
+                                       self.cell[i].set_property('editable', True)
+                                       self.cell[i].connect("edited", self._on_col_edited, i)
+                                       self.tvcolumn[i] = gtk.TreeViewColumn(
+                                               self.liststorehandler.get_colname(i), self.cell[i]
+                                       )
+                                       self.tvcolumn[i].set_attributes( self.cell[i], text = i)
+                               elif i in [4, 6]: # unit, priority
                                        self.cell[i] = gtk.CellRendererCombo()
-                                       self.tvcolumn[i] = gtk.TreeViewColumn(self.liststorehandler.get_colname(i), self.cell[i])
                                        self.cell[i].set_property("model", m)
                                        self.cell[i].set_property('text-column', i)
                                        self.cell[i].set_property('editable', True)
-                                       self.cell[i].connect("edited", self.col_edited, i)
+                                       self.cell[i].connect("edited", self._on_col_edited, i)
+                                       self.tvcolumn[i] = gtk.TreeViewColumn(
+                                               self.liststorehandler.get_colname(i), self.cell[i]
+                                       )
                                        self.tvcolumn[i].set_attributes( self.cell[i], text = i)
                                else:
                                        self.cell[i] = gtk.CellRendererText()
-                                       self.tvcolumn[i] = gtk.TreeViewColumn(self.liststorehandler.get_colname(i), self.cell[i])
                                        self.cell[i].set_property('editable', True)
                                        self.cell[i].set_property('editable-set', True)
-                                       self.cell[i].connect("edited", self.col_edited, i)
-                                       #self.cell[i].connect("editing-canceled", self.col_edited2, i) 
+                                       self.cell[i].connect("edited", self._on_col_edited, i)
+                                       self.tvcolumn[i] = gtk.TreeViewColumn(
+                                               self.liststorehandler.get_colname(i), self.cell[i]
+                                       )
                                        self.tvcolumn[i].set_attributes(self.cell[i], text = i)
 
-                               self.cell[i].set_property('cell-background', 'lightgray')
                                self.tvcolumn[i].set_sort_column_id(i)
                                self.tvcolumn[i].set_resizable(True)
                                self.treeview.append_column(self.tvcolumn[i])
 
-               # Disable drag and drop reordering of rows
-               self.treeview.set_reorderable(False)
-
                if self.scrolled_window is not None:
                        self.scrolled_window.destroy()
 
@@ -433,3 +289,27 @@ class View(gtk.VBox):
                self.loadList()
 
                self.show_all()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_col_edited(self, cell, irow, new_text, icol = None):
+               if (irow != 4):
+                       self.liststorehandler.update_row(irow, icol, new_text)
+               else:
+                       print cell, irow, new_text, icol
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_col_toggled(self, widget, irow, status):
+               ls = self.treeview.get_model()
+
+               if self.liststorehandler.get_filter() == self.liststorehandler.SHOW_ACTIVE:
+                       if ls[irow][1] == "0":
+                               self.liststorehandler.update_row(irow, 1, "1")
+                       else:
+                               self.liststorehandler.update_row(irow, 1, "0")
+               else:
+                       if ls[irow][1] == "1":
+                               self.liststorehandler.update_row(irow, 1, "-1")
+                       elif ls[irow][1] == "0":
+                               self.liststorehandler.update_row(irow, 1, "1")
+                       else:
+                               self.liststorehandler.update_row(irow, 1, "0")