1 '''A module to handle a debug console'''
8 '''The window containing the debug info'''
9 def __init__(self
, debug_manager
):
10 self
.window
= gtk
.Window(gtk
.WINDOW_TOPLEVEL
)
11 self
.window
.set_title("debug")
12 self
.window
.connect("delete_event", self
.on_delete
)
13 self
.store
= DebugStore(debug_manager
)
14 self
.view
= DebugView(self
.store
)
15 self
.scroll_view
= gtk
.ScrolledWindow()
16 self
.scroll_view
.add(self
.view
)
19 self
.vbox
= gtk
.VBox()
20 self
.filter_box
= gtk
.HBox()
21 self
.buttons_box
= gtk
.HBox()
22 self
.test_box
= gtk
.HBox()
24 self
.filter_entry
= gtk
.Entry()
25 self
.filter_btn
= gtk
.Button("Filter")
26 self
.filter_box
.pack_start(self
.filter_entry
)
27 self
.filter_box
.pack_start(self
.filter_btn
, False)
28 self
.vbox
.pack_start(self
.filter_box
, False)
30 self
.vbox
.pack_start(self
.scroll_view
)
32 self
.close_btn
= gtk
.Button("Close")
33 self
.buttons_box
.pack_end(self
.close_btn
, False)
34 self
.vbox
.pack_start(self
.buttons_box
, False)
36 self
.test_entry
= gtk
.Entry()
37 self
.test_add
= gtk
.Button("Add")
38 self
.test_box
.pack_start(self
.test_entry
)
39 self
.test_box
.pack_start(self
.test_add
, False)
40 self
.vbox
.pack_start(self
.test_box
, False)
43 self
.window
.add(self
.vbox
)
45 self
.filter_btn
.connect("clicked", self
.on_filter_clicked
)
46 self
.filter_entry
.connect("activate", self
.on_filter_clicked
)
47 self
.close_btn
.connect("clicked", self
.on_close
)
48 self
.test_add
.connect("clicked", self
.on_add
)
49 self
.test_entry
.connect("activate", self
.on_add
)
52 '''shows the window'''
53 self
.window
.show_all()
55 def on_filter_clicked(self
, button
, data
=None):
56 '''used when the filter button is clicked'''
57 pattern
= self
.filter_entry
.get_text()
58 self
.view
.filter_caller(pattern
)
60 def on_add(self
, button
, data
=None):
61 caller
= self
.test_entry
.get_text()
62 #self.store.append([caller, "just a test"])
63 self
.store
.add({'category':caller
, 'message':'just a test'})
65 def on_close(self
, button
, data
=None):
69 def on_delete(self
, widget
, event
, data
=None):
73 class DebugView( gtk
.TextView
):
74 '''A TextView optimized for debug consoles'''
75 def __init__(self
, store
):
76 gtk
.TextView
.__init
__(self
)
78 self
.buffer = DebugBuffer(store
)
79 self
.set_buffer(self
.buffer)
81 self
.set_editable(False)
83 def filter_caller(self
, pattern
):
84 self
.store
.filter_caller(pattern
)
85 self
.buffer = DebugBuffer(self
.store
.filter)
86 self
.set_buffer(self
.buffer)
88 class DebugBuffer( gtk
.TextBuffer
):
89 '''A TextBuffer based on a ListStore'''
90 def __init__(self
, store
):
91 gtk
.TextBuffer
.__init
__(self
)
94 self
.create_tag("caller", weight
=pango
.WEIGHT_BOLD
)
95 self
.create_tag("message")
97 self
.iter = self
.get_start_iter()
99 self
.insert_with_tags_by_name(self
.iter, row
[0], "caller")
100 self
.insert_with_tags_by_name(self
.iter, ": " + row
[1], "message")
101 self
.insert(self
.iter, '\n')
103 store
.connect("row-changed", self
.on_store_insert
)
106 def on_store_insert(self
, model
, path
, iter):
107 caller
= model
.get_value(iter, 0)
108 message
= model
.get_value(iter, 1)
109 if caller
and message
:
110 self
.insert_with_tags_by_name(self
.iter, caller
, "caller")
111 self
.insert_with_tags_by_name(self
.iter, ": " + message
+ '\n', "message")
113 class DebugStore( gtk
.ListStore
):
114 '''A ListStore with filtering and more, optimized for debug'''
115 def __init__( self
, debug_manager
):
117 gtk
.ListStore
.__init
__(self
, str, str) #caller, message
118 self
.debug_manager
= debug_manager
119 self
.filter = self
.filter_new()
121 for message
in debug_manager
.get_all():
122 self
.on_message_added(message
)
123 debug_manager
.connect('message-added', self
.on_message_added
)
125 def on_message_added(self
, message
):
126 self
.append([message
['category'], message
['message']])
128 def add(self
, message
):
129 #a "pure" debugstore shouldn't have this, but it's just to test sth
130 self
.debug_manager
.add(message
)
132 def filter_caller( self
, name
):
133 '''displays only the messages whose caller matches "name"'''
135 self
.filter = self
.filter_new()
136 self
.filter.set_visible_func(filter_func
, name
)
138 def filter_func(model
, iter, name
):
139 '''returns true if the caller column matches name'''
140 caller
= model
.get_value(iter, 0)
143 if caller
.find(name
) == -1:
148 '''Manages debug informations, events and cleanups'''
151 self
.messages
= [] #list of messages, each one is a dict
152 self
.message_limit
= -1
154 self
.__event
_callbacks
= {}
156 def set_size_limit(self
, limit
):
157 '''maximum size of the messages list, -1 is infinite'''
158 self
.message_limit
= limit
160 def add(self
, message
):
161 '''add the message'''
162 #message is {'category': 'misc', 'message':'foo', 'priority':'low',...}
163 if len(self
.messages
) == self
.message_limit
:
164 self
.emit('message-removed', self
.messages
[0])
167 self
.messages
.append(message
)
168 self
.emit('message-added', message
)
171 '''get all messages'''
175 '''return the nth message'''
176 return self
.messages
[n
]
179 def emit(self
, event_name
, *args
):
180 '''emits the signal named event_name'''
181 if event_name
not in self
.__event
_callbacks
:
183 for callback
in self
.__event
_callbacks
[event_name
]:
186 def connect(self
, event_name
, callback
):
187 '''connect the event called "event_name" with the callback'''
188 if event_name
not in self
.__event
_callbacks
:
189 self
.__event
_callbacks
[event_name
] = []
190 self
.__event
_callbacks
[event_name
].append(callback
)
192 def simple_print(message
):
196 if __name__
== '__main__':
197 debug_manager
= DebugManager()
198 debug_manager
.set_size_limit(1)
199 debug_manager
.connect('message-added', simple_print
)
200 debug_manager
.add({'category':'core', 'message':'something happened'})
201 debug_manager
.add({'category':'ui', 'message':'WTF??'})
202 app
= DebugWindow(debug_manager
)