Added set_size_limit: will delete older messages when the db becomes too big
[debug_console.git] / DebugWindow.py
blobe5fc4757a3f5e093f2cc0013c6546c3fdd388313
1 '''A module to handle a debug console'''
2 import gtk
3 import pango
6 class DebugWindow():
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)
51 def show( self ):
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):
66 gtk.main_quit()
67 return False
69 def on_delete(self, widget, event, data=None):
70 gtk.main_quit()
71 return False
73 class DebugView( gtk.TextView ):
74 '''A TextView optimized for debug consoles'''
75 def __init__(self, store):
76 gtk.TextView.__init__(self)
77 self.store = store
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)
92 self.store = store
94 self.create_tag("caller", weight=pango.WEIGHT_BOLD)
95 self.create_tag("message")
97 self.iter = self.get_start_iter()
98 for row in store:
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 ):
116 '''constructor'''
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"'''
134 del self.filter
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)
141 if not caller:
142 return False
143 if caller.find(name) == -1:
144 return False
145 return True
147 class DebugManager:
148 '''Manages debug informations, events and cleanups'''
149 def __init__(self):
150 '''constructor'''
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])
165 self.messages.pop(0)
167 self.messages.append(message)
168 self.emit('message-added', message)
170 def get_all(self):
171 '''get all messages'''
172 return self.messages
174 def get_n(self, n):
175 '''return the nth message'''
176 return self.messages[n]
178 #Event handling
179 def emit(self, event_name, *args):
180 '''emits the signal named event_name'''
181 if event_name not in self.__event_callbacks:
182 return
183 for callback in self.__event_callbacks[event_name]:
184 callback(*args)
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):
193 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)
203 app.show()
204 gtk.main()