Adding paranoia protection
[multilist] / src / libview.py
index df6be0e..0a6b942 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,62 +41,10 @@ except NameError:
 _moduleLogger = logging.getLogger(__name__)
 
 
-class Columns_dialog(gtk.VBox):
-
-       def __init__(self, db, liststorehandler):
-               gtk.VBox.__init__(self, homogeneous = False, spacing = 0)
-
-               self.db = db
-               self.liststorehandler = liststorehandler
-
-               #serverbutton = gtk.ToggleButton("SyncServer starten")
-               #serverbutton.connect("clicked", self.startServer, (None, ))
-               #self.pack_start(serverbutton, expand = False, fill = True, padding = 1)
-               #print "x1"
-
-               frame = gtk.Frame(_("Columns"))
-               self.framebox = gtk.VBox(homogeneous = False, spacing = 0)
-
-               self.scrolled_window = gtk.ScrolledWindow()
-               self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-
-               self.scrolled_window.add_with_viewport(self.framebox)
-
-               i = 1 #uid can not be shown
-               while self.liststorehandler.get_colname(i) is not None:
-                       name = str(self.liststorehandler.get_colname(i))
-                       checkbutton = gtk.CheckButton(name)
-                       if self.db.ladeDirekt("showcol_"+name) == "1":
-                               checkbutton.set_active(True)
+class TripleToggleCellRenderer(gtk.CellRendererToggle):
 
-                       self.framebox.pack_start(checkbutton)
-                       i = i+1
-
-               frame.add(self.scrolled_window)
-               self.pack_start(frame, expand = True, fill = True, padding = 1)
-
-       def is_col_selected(self, icol):
-               children = self.framebox.get_children()
-               if icol < len(children):
-                       return children[icol].get_active()
-               else:
-                       return None
-
-       def save_column_setting(self):
-               i = 1 #uid can not be shown
-               while self.liststorehandler.get_colname(i) is not None:
-                       name = str(self.liststorehandler.get_colname(i))
-                       if self.is_col_selected(i-1) == True:
-                               self.db.speichereDirekt("showcol_"+name, "1")
-                       else:
-                               self.db.speichereDirekt("showcol_"+name, "0")
-                       i += 1
-
-
-class CellRendererTriple(gtk.GenericCellRenderer):
        __gproperties__ = {
-               "status": (gobject.TYPE_STRING, "Status",
-               "Status", "", gobject.PARAM_READWRITE),
+               "status": (gobject.TYPE_STRING, "Status", "Status", "", gobject.PARAM_READWRITE),
        }
 
        __gsignals__ = {
@@ -101,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))
@@ -305,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)
 
 
@@ -380,41 +198,19 @@ class View(gtk.VBox):
 
                logging.info("libview, init")
 
-               self.scrolled_window = None
+               self.treeview = None
+               self.scrolled_window = gtk.ScrolledWindow()
+               self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+               self.pack_start(self.scrolled_window, expand = True, fill = True, padding = 0)
+
+               self.scrolled_window = hildonize.hildonize_scrollwindow_with_viewport(self.scrolled_window)
+
                self.reload_view()
 
        def loadList(self):
                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:
@@ -422,16 +218,16 @@ 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())
                self.modelsort.set_sort_column_id(2, gtk.SORT_ASCENDING)
 
+               if self.treeview is not None:
+                       self.scrolled_window.remove(self.treeview)
                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())
@@ -439,51 +235,90 @@ class View(gtk.VBox):
                m = self.liststorehandler.get_unitsstore()
 
                for i in range(self.liststorehandler.get_colcount()):
-                       if 5 < i:
-                               default = "0"
-                       else:
+                       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 == 1):
-                                       self.cell[i] = CellRendererTriple()
-                                       self.tvcolumn[i] =      gtk.TreeViewColumn("", self.cell[i])
-                                       self.cell[i].connect( 'status_changed', self.col_toggled)
+                               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.tvcolumn[i].set_attributes( self.cell[i], status = i)
-                               elif (i == 3)or(i == 4)or(i == 6):
+                               elif i in [3, 5]: # quantity, price
+                                       self.cell[i] = gtk.CellRendererSpin()
+                                       try:
+                                               # Python 2.6 is much cleaner
+                                               floatMin = -sys.float_info.min
+                                               floatMax = sys.float_info.max
+                                       except AttributeError:
+                                               # Python 2.5 support
+                                               floatMin = -1.79e308
+                                               floatMax = 1.79e308
+                                       adjustment = gtk.Adjustment(0, floatMin, floatMax, 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)
-
-                               if (i>0):
-                                       self.treeview.append_column(self.tvcolumn[i])
-
-               # Allow NOT drag and drop reordering of rows
-               self.treeview.set_reorderable(False)
-
-               if self.scrolled_window is not None:
-                       self.scrolled_window.destroy()
-
-               self.scrolled_window = gtk.ScrolledWindow()
-               self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+                               self.treeview.append_column(self.tvcolumn[i])
 
                self.scrolled_window.add(self.treeview)
-               self.pack_start(self.scrolled_window, expand = True, fill = True, padding = 0)
                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")