|         |      1 import gtk, gobject, pango | 
|         |      2 from cgi import escape | 
|         |      3  | 
|         |      4  | 
|         |      5 class DataView(gtk.ScrolledWindow): | 
|         |      6     def __init__(self): | 
|         |      7         super(DataView, self).__init__() | 
|         |      8  | 
|         |      9         sw = self | 
|         |     10         sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | 
|         |     11         sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) | 
|         |     12         self.treeview = gtk.TreeView(gtk.ListStore(str)) | 
|         |     13         self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE) | 
|         |     14         self.treeview.set_property("rubber-banding", True) | 
|         |     15         sw.add(self.treeview) | 
|         |     16  | 
|         |     17  | 
|         |     18     def load_data(self, names, rows): | 
|         |     19         x = [str] * (len(names) + 1) | 
|         |     20         liststore = gtk.ListStore(*x) | 
|         |     21  | 
|         |     22         for c in self.treeview.get_columns(): | 
|         |     23             self.treeview.remove_column(c) | 
|         |     24  | 
|         |     25         tvcolumn = gtk.TreeViewColumn() | 
|         |     26         cell = DataViewCellRenderer() | 
|         |     27         cell.set_property('head', True) | 
|         |     28         tvcolumn.pack_start(cell, True) | 
|         |     29         tvcolumn.set_property('resizable', True) | 
|         |     30         #tvcolumn.set_property('sizing', gtk.TREE_VIEW_COLUMN_FIXED) | 
|         |     31         tvcolumn.set_attributes(cell, text=0) | 
|         |     32         tvcolumn.set_min_width(2) | 
|         |     33         self.treeview.append_column(tvcolumn) | 
|         |     34  | 
|         |     35         i = 0 | 
|         |     36         for c in names: | 
|         |     37             i += 1 | 
|         |     38             typename = c[1] | 
|         |     39             title = '<b>%s</b>' % escape(c[0]) | 
|         |     40             if typename: | 
|         |     41                 title += '\n<span size="small">%s</span>' % typename | 
|         |     42  | 
|         |     43             tvcolumn = gtk.TreeViewColumn() | 
|         |     44             cell = DataViewCellRenderer() | 
|         |     45  | 
|         |     46             lab = gtk.Label() | 
|         |     47             lab.set_use_underline(False) | 
|         |     48             lab.set_markup(title) | 
|         |     49             lab.show() | 
|         |     50             tvcolumn.set_widget(lab) | 
|         |     51             tvcolumn.set_property('resizable', True) | 
|         |     52             tvcolumn.pack_start(cell, True) | 
|         |     53             tvcolumn.set_attributes(cell, text=i) | 
|         |     54  | 
|         |     55             self.treeview.append_column(tvcolumn) | 
|         |     56  | 
|         |     57         self.treeview.set_model(liststore) | 
|         |     58  | 
|         |     59         i = 0 | 
|         |     60         for row in rows: | 
|         |     61             i += 1 | 
|         |     62             liststore.append([i]+list(row)) | 
|         |     63  | 
|         |     64  | 
|         |     65  | 
|         |     66 class DataViewCellRenderer(gtk.GenericCellRenderer): | 
|         |     67     __gtype_name__ = 'DataViewCellRenderer' | 
|         |     68     __gproperties__ = { | 
|         |     69         'text': (gobject.TYPE_STRING, None, None, '', gobject.PARAM_READWRITE), | 
|         |     70         'head': (gobject.TYPE_BOOLEAN, None, None, False, gobject.PARAM_READWRITE)} | 
|         |     71  | 
|         |     72  | 
|         |     73     def __init__(self): | 
|         |     74         gtk.GenericCellRenderer.__init__(self) | 
|         |     75         self._props = {'text' : '', 'head' : False} | 
|         |     76  | 
|         |     77  | 
|         |     78     def do_set_property(self, pspec, value): | 
|         |     79         if not pspec.name in self._props: | 
|         |     80             raise AttributeError, 'Unknown property: %s' % pspec.name | 
|         |     81         self._props[pspec.name] = value | 
|         |     82  | 
|         |     83  | 
|         |     84     def do_get_property(self, pspec): | 
|         |     85         return self._props[pspec.name] | 
|         |     86  | 
|         |     87  | 
|         |     88     def on_get_size(self, widget, cell_area): | 
|         |     89         if cell_area == None: | 
|         |     90             pangoctx = widget.get_pango_context() | 
|         |     91             layout = pango.Layout(pangoctx) | 
|         |     92             layout.set_width(-1) | 
|         |     93             layout.set_text(self.get_property('text') or 'NULL') | 
|         |     94             w,h = layout.get_pixel_size() | 
|         |     95             return (0, 0, w+5, 20) | 
|         |     96         x = cell_area.x | 
|         |     97         y = cell_area.x | 
|         |     98         w = cell_area.width | 
|         |     99         h = cell_area.height | 
|         |    100  | 
|         |    101         return (x,y,w,h) | 
|         |    102  | 
|         |    103  | 
|         |    104     def on_render(self, window, widget, background_area, cell_area, expose_area, flags): | 
|         |    105         x = background_area.x | 
|         |    106         y = background_area.y | 
|         |    107         w = background_area.width | 
|         |    108         h = background_area.height | 
|         |    109  | 
|         |    110         ctx = window.cairo_create() | 
|         |    111         ctx.set_line_width(0.4) | 
|         |    112         ctx.set_source_rgb(0, 0, 0) | 
|         |    113         ctx.move_to(x+w-1.5, y-0.5) | 
|         |    114         ctx.line_to(x+w-1.5, y+h-0.5) | 
|         |    115         ctx.line_to(x-0.5, y+h-0.5) | 
|         |    116         ctx.stroke() | 
|         |    117         ctx.set_source_rgb(1, 1, 1) | 
|         |    118         ctx.move_to(x+w-0.5, y-0.5) | 
|         |    119         ctx.line_to(x+w-0.5, y+h-0.5) | 
|         |    120         ctx.stroke() | 
|         |    121  | 
|         |    122         pangoctx = widget.get_pango_context() | 
|         |    123         layout = pango.Layout(pangoctx) | 
|         |    124         text = self.get_property('text') | 
|         |    125         head = self.get_property('head') | 
|         |    126  | 
|         |    127         if head: | 
|         |    128             layout.set_markup('<b>%s</b>' % text) | 
|         |    129         else: | 
|         |    130             if text is None: | 
|         |    131                 layout.set_markup('<span foreground="gray">NULL</span>') | 
|         |    132             else: | 
|         |    133                 layout.set_text(text) | 
|         |    134  | 
|         |    135         widget.style.paint_layout(window, gtk.STATE_NORMAL, True, | 
|         |    136                                 cell_area, widget, '', | 
|         |    137                                 cell_area.x, cell_area.y, | 
|         |    138                                 layout) | 
|         |    139  |