1 |
#!/usr/bin/env python |
2 |
|
3 |
import gi |
4 |
gi.require_version('Gtk', '3.0') |
5 |
from gi.repository import Gtk |
6 |
|
7 |
class Browser: |
8 |
def make_row( self, piter, name, value ): |
9 |
info = repr(value) |
10 |
if not hasattr(value, "__dict__"): |
11 |
if len(info) > 80: |
12 |
# it's a big list, or dict etc. |
13 |
info = info[:80] + "..." |
14 |
_piter = self.treestore.append( piter, [ name, type(value).__name__, info ] ) |
15 |
return _piter |
16 |
|
17 |
def make_instance( self, value, piter ): |
18 |
if hasattr( value, "__dict__" ): |
19 |
for _name, _value in value.__dict__.items(): |
20 |
_piter = self.make_row( piter, "."+_name, _value ) |
21 |
_path = self.treestore.get_path( _piter ) |
22 |
self.otank[ _path.to_string() ] = (_name, _value) |
23 |
|
24 |
def make_mapping( self, value, piter ): |
25 |
keys = [] |
26 |
if hasattr( value, "iteritems"): |
27 |
for k,v in value.iteritems(): |
28 |
_name = "[%s]"%str(k) |
29 |
_piter = self.make_row( piter, _name, v ) |
30 |
_path = self.treestore.get_path( _piter ) |
31 |
self.otank[_path.to_string()] = (_name, v) |
32 |
return |
33 |
elif hasattr(value,'__getitem__') and hasattr(value,'__len__') and len(value) > 1: |
34 |
keys = range(len(value)) |
35 |
elif hasattr(value,"__iter__"): |
36 |
# handle 'set' objects... |
37 |
for v in value: |
38 |
_name = "..." |
39 |
_piter = self.make_row(piter,_name, v) |
40 |
_path = self.treestore.get_path(_piter) |
41 |
self.otank[_path.to_string()] = (_name,v) |
42 |
return |
43 |
|
44 |
for key in keys: |
45 |
_name = "[%s]"%str(key) |
46 |
_piter = self.make_row( piter, _name, value[key] ) |
47 |
_path = self.treestore.get_path( _piter ) |
48 |
self.otank[_path.to_string()] = (_name, value[key]) |
49 |
|
50 |
def make(self, name=None, value=None, path=None, depth=1): |
51 |
if path is None: |
52 |
# make root node |
53 |
piter = self.make_row( None, name, value ) |
54 |
path = self.treestore.get_path( piter ) |
55 |
self.otank[path.to_string()] = (name, value) |
56 |
else: |
57 |
name, value = self.otank[path.to_string()] |
58 |
|
59 |
piter = self.treestore.get_iter( path ) |
60 |
if not self.treestore.iter_has_child( piter ): |
61 |
self.make_mapping( value, piter ) |
62 |
self.make_instance( value, piter ) |
63 |
|
64 |
if depth: |
65 |
for i in range( self.treestore.iter_n_children( piter ) ): |
66 |
tmp_path = path.copy() |
67 |
tmp_path.append_index(i) |
68 |
self.make( path = tmp_path, depth = depth - 1 ) |
69 |
|
70 |
def row_expanded( self, treeview, piter, path ): |
71 |
self.make( path = path ) |
72 |
|
73 |
def delete_event(self, widget, event, data=None): |
74 |
if self.quit: |
75 |
Gtk.main_quit() |
76 |
return False |
77 |
|
78 |
def __init__(self, name, value, quit=False): |
79 |
self.window = Gtk.Window(Gtk.WindowType.TOPLEVEL) |
80 |
self.window.set_title("Browser") |
81 |
self.window.set_size_request(512, 320) |
82 |
self.window.connect("delete_event", self.delete_event) |
83 |
self.quit = quit |
84 |
|
85 |
# we will store the name, the type name, and the repr |
86 |
columns = [str,str,str] |
87 |
self.treestore = Gtk.TreeStore(*columns) |
88 |
|
89 |
# the otank tells us what object we put at each node in the tree |
90 |
self.otank = {} # map path -> (name,value) |
91 |
self.make( name, value ) |
92 |
|
93 |
self.treeview = Gtk.TreeView(self.treestore) |
94 |
self.treeview.connect("row-expanded", self.row_expanded ) |
95 |
|
96 |
self.tvcolumns = [ Gtk.TreeViewColumn() for _type in columns ] |
97 |
i = 0 |
98 |
for tvcolumn in self.tvcolumns: |
99 |
self.treeview.append_column(tvcolumn) |
100 |
cell = Gtk.CellRendererText() |
101 |
tvcolumn.pack_start(cell, True) |
102 |
tvcolumn.add_attribute(cell, 'text', i) |
103 |
i = i + 1 |
104 |
|
105 |
view = Gtk.ScrolledWindow() |
106 |
view.add_with_viewport(self.treeview) |
107 |
self.window.add(view) |
108 |
#self.window.add(self.treeview) |
109 |
self.window.show_all() |
110 |
|
111 |
|
112 |
def dump( name, value ): |
113 |
browser = Browser(name, value, quit=True) |
114 |
Gtk.main() |
115 |
|
116 |
def test(): |
117 |
class Nil: |
118 |
pass |
119 |
a = Nil() |
120 |
b = Nil() |
121 |
c = Nil() |
122 |
d = Nil() |
123 |
a.b=b |
124 |
a.x=set([3,4,5]) |
125 |
b.c=c |
126 |
c.d=d |
127 |
d.a=a # circular chain |
128 |
dump( "a", a ) |
129 |
|
130 |
if __name__ == "__main__": |
131 |
test() |
132 |
|