1 |
jpye |
1957 |
#!/usr/bin/env python |
2 |
|
|
|
3 |
adrian |
2890 |
import gi |
4 |
|
|
gi.require_version('Gtk', '3.0') |
5 |
|
|
from gi.repository import Gtk |
6 |
jpye |
1957 |
|
7 |
|
|
class Browser: |
8 |
jpye |
1964 |
def make_row( self, piter, name, value ): |
9 |
|
|
info = repr(value) |
10 |
|
|
if not hasattr(value, "__dict__"): |
11 |
|
|
if len(info) > 80: |
12 |
adrian |
2890 |
# it's a big list, or dict etc. |
13 |
|
|
info = info[:80] + "..." |
14 |
jpye |
1964 |
_piter = self.treestore.append( piter, [ name, type(value).__name__, info ] ) |
15 |
|
|
return _piter |
16 |
jpye |
1957 |
|
17 |
jpye |
1964 |
def make_instance( self, value, piter ): |
18 |
|
|
if hasattr( value, "__dict__" ): |
19 |
|
|
for _name, _value in value.__dict__.items(): |
20 |
adrian |
2890 |
_piter = self.make_row( piter, "."+_name, _value ) |
21 |
|
|
_path = self.treestore.get_path( _piter ) |
22 |
adrian |
2898 |
self.otank[ _path.to_string() ] = (_name, _value) |
23 |
jpye |
1957 |
|
24 |
jpye |
1964 |
def make_mapping( self, value, piter ): |
25 |
jpye |
1957 |
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 |
adrian |
2898 |
self.otank[_path.to_string()] = (_name, v) |
32 |
jpye |
1957 |
return |
33 |
adrian |
2921 |
elif hasattr(value,'__getitem__') and hasattr(value,'__len__') and len(value) > 1: |
34 |
jpye |
1965 |
keys = range(len(value)) |
35 |
jpye |
1957 |
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 |
adrian |
2898 |
self.otank[_path.to_string()] = (_name,v) |
42 |
jpye |
1957 |
return |
43 |
jpye |
1965 |
|
44 |
jpye |
1957 |
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 |
adrian |
2898 |
self.otank[_path.to_string()] = (_name, value[key]) |
49 |
jpye |
1957 |
|
50 |
jpye |
1964 |
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 |
adrian |
2898 |
self.otank[path.to_string()] = (name, value) |
56 |
jpye |
1964 |
else: |
57 |
adrian |
2898 |
name, value = self.otank[path.to_string()] |
58 |
jpye |
1957 |
|
59 |
jpye |
1964 |
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 |
jpye |
1957 |
|
64 |
jpye |
1964 |
if depth: |
65 |
|
|
for i in range( self.treestore.iter_n_children( piter ) ): |
66 |
adrian |
2890 |
tmp_path = path.copy() |
67 |
|
|
tmp_path.append_index(i) |
68 |
|
|
self.make( path = tmp_path, depth = depth - 1 ) |
69 |
jpye |
1957 |
|
70 |
jpye |
1964 |
def row_expanded( self, treeview, piter, path ): |
71 |
|
|
self.make( path = path ) |
72 |
jpye |
1957 |
|
73 |
jpye |
1964 |
def delete_event(self, widget, event, data=None): |
74 |
|
|
if self.quit: |
75 |
adrian |
2890 |
Gtk.main_quit() |
76 |
jpye |
1964 |
return False |
77 |
jpye |
1957 |
|
78 |
jpye |
1984 |
def __init__(self, name, value, quit=False): |
79 |
adrian |
2890 |
self.window = Gtk.Window(Gtk.WindowType.TOPLEVEL) |
80 |
jpye |
1963 |
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 |
jpye |
1957 |
|
85 |
jpye |
1963 |
# we will store the name, the type name, and the repr |
86 |
|
|
columns = [str,str,str] |
87 |
adrian |
2890 |
self.treestore = Gtk.TreeStore(*columns) |
88 |
jpye |
1957 |
|
89 |
jpye |
1963 |
# 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 |
jpye |
1957 |
|
93 |
adrian |
2890 |
self.treeview = Gtk.TreeView(self.treestore) |
94 |
jpye |
1963 |
self.treeview.connect("row-expanded", self.row_expanded ) |
95 |
jpye |
1957 |
|
96 |
adrian |
2890 |
self.tvcolumns = [ Gtk.TreeViewColumn() for _type in columns ] |
97 |
jpye |
1963 |
i = 0 |
98 |
|
|
for tvcolumn in self.tvcolumns: |
99 |
|
|
self.treeview.append_column(tvcolumn) |
100 |
adrian |
2890 |
cell = Gtk.CellRendererText() |
101 |
jpye |
1963 |
tvcolumn.pack_start(cell, True) |
102 |
|
|
tvcolumn.add_attribute(cell, 'text', i) |
103 |
|
|
i = i + 1 |
104 |
jpye |
1957 |
|
105 |
adrian |
2890 |
view = Gtk.ScrolledWindow() |
106 |
jpye |
1963 |
view.add_with_viewport(self.treeview) |
107 |
|
|
self.window.add(view) |
108 |
jpye |
1964 |
#self.window.add(self.treeview) |
109 |
jpye |
1963 |
self.window.show_all() |
110 |
jpye |
1957 |
|
111 |
jpye |
1964 |
|
112 |
jpye |
1957 |
def dump( name, value ): |
113 |
adrian |
2890 |
browser = Browser(name, value, quit=True) |
114 |
|
|
Gtk.main() |
115 |
jpye |
1957 |
|
116 |
|
|
def test(): |
117 |
adrian |
2890 |
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 |
jpye |
1957 |
|
130 |
|
|
if __name__ == "__main__": |
131 |
adrian |
2890 |
test() |
132 |
jpye |
1957 |
|