1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 """An input/output window for the glade reactor inspector.
12 from twisted.python.util import sibpath
13 from twisted.python import reflect
15 from twisted.manhole.ui import gtk2manhole
16 from twisted.python.components import Adapter, registerAdapter
17 from twisted.python import log
18 from twisted.protocols import policies
19 from zope.interface import implements, Interface
21 # the glade file uses stock icons, which requires gnome to be installed
23 version = "$Revision: 1.1 $"[11:-2]
24 gnome.init("gladereactor Inspector", version)
26 class ConsoleOutput(gtk2manhole.ConsoleOutput):
27 def _captureLocalLog(self):
28 self.fobs = log.FileLogObserver(gtk2manhole._Notafile(self, "log"))
35 class ConsoleInput(gtk2manhole.ConsoleInput):
36 def sendMessage(self):
37 buffer = self.textView.get_buffer()
38 iter1, iter2 = buffer.get_bounds()
39 text = buffer.get_text(iter1, iter2, False)
43 self.toplevel.do(text)
45 class INode(Interface):
46 """A node in the inspector tree model.
49 def __adapt__(adaptable, default):
50 if hasattr(adaptable, "__dict__"):
51 return InstanceNode(adaptable)
52 return AttributesNode(adaptable)
54 class InspectorNode(Adapter):
57 def postInit(self, offset, parent, slot):
65 while x.parent is not None:
71 def __getitem__(self, index):
72 slot, o = self.get(index)
73 n = INode(o, persist=False)
74 n.postInit(index, self, slot)
78 return str(self.original)
81 return (self.slot, self.origstr())
84 class ConstantNode(InspectorNode):
88 class DictionaryNode(InspectorNode):
90 L = self.original.items()
95 return len(self.original)
100 class ListNode(InspectorNode):
101 def get(self, index):
102 return index, self.original[index]
108 return len(self.original)
110 class AttributesNode(InspectorNode):
112 return len(dir(self.original))
114 def get(self, index):
115 L = dir(self.original)
117 return L[index], getattr(self.original, L[index])
119 class InstanceNode(InspectorNode):
121 return len(self.original.__dict__) + 1
123 def get(self, index):
125 if hasattr(self.original, "__class__"):
126 v = self.original.__class__
128 v = type(self.original)
129 return "__class__", v
132 L = self.original.__dict__.items()
138 for x in dict, types.DictProxyType:
139 registerAdapter(DictionaryNode, x, INode)
140 for x in list, tuple:
141 registerAdapter(ListNode, x, INode)
143 registerAdapter(ConstantNode, x, INode)
146 class InspectorTreeModel(gtk.GenericTreeModel):
147 def __init__(self, root):
148 gtk.GenericTreeModel.__init__(self)
149 self.root = INode(root, persist=False)
150 self.root.postInit(0, None, 'root')
152 def on_get_flags(self):
155 def on_get_n_columns(self):
158 def on_get_column_type(self, index):
159 return gobject.TYPE_STRING
161 def on_get_path(self, node):
162 return node.getPath()
164 def on_get_iter(self, path):
170 def on_get_value(self, node, column):
171 return node.format()[column]
173 def on_iter_next(self, node):
175 return node.parent[node.offset + 1]
179 def on_iter_children(self, node):
182 def on_iter_has_child(self, node):
185 def on_iter_n_children(self, node):
188 def on_iter_nth_child(self, node, n):
193 def on_iter_parent(self, node):
199 def __init__(self, o=None):
200 self.xml = x = gtk.glade.XML(sibpath(__file__, "inspectro.glade"))
201 self.tree_view = x.get_widget("treeview")
202 colnames = ["Name", "Value"]
203 for i in range(len(colnames)):
204 self.tree_view.append_column(
206 colnames[i], gtk.CellRendererText(), text=i))
208 for m in reflect.prefixedMethods(self, "on_"):
209 d[m.im_func.__name__] = m
210 self.xml.signal_autoconnect(d)
213 self.ns = {'inspect': self.inspect}
214 iwidget = x.get_widget('input')
215 self.input = ConsoleInput(iwidget)
216 self.input.toplevel = self
217 iwidget.connect("key_press_event", self.input._on_key_press_event)
218 self.output = ConsoleOutput(x.get_widget('output'))
223 self.xml.get_widget("itname").set_text(repr(o))
224 self.xml.get_widget("itpath").set_text("???")
226 def inspect(self, o):
227 self.model = InspectorTreeModel(o)
228 self.tree_view.set_model(self.model)
231 def do(self, command):
232 filename = '<inspector>'
236 code = compile(command, filename, 'eval')
238 code = compile(command, filename, 'single')
239 val = eval(code, self.ns, self.ns)
246 def on_inspect(self, *a):
247 self.inspect(self.selected)
249 def on_inspect_new(self, *a):
250 Inspectro(self.selected)
252 def on_row_activated(self, tv, path, column):
253 self.select(self.model.on_get_iter(path).original)
256 class LoggingProtocol(policies.ProtocolWrapper):
257 """Log network traffic."""
262 def __init__(self, *args):
263 policies.ProtocolWrapper.__init__(self, *args)
267 def write(self, data):
269 self.outLog.append((time.time(), data))
271 self.logViewer.updateOut(self.outLog[-1])
272 policies.ProtocolWrapper.write(self, data)
274 def dataReceived(self, data):
276 self.inLog.append((time.time(), data))
278 self.logViewer.updateIn(self.inLog[-1])
279 policies.ProtocolWrapper.dataReceived(self, data)
282 r = "wrapped " + repr(self.wrappedProtocol)
288 class LoggingFactory(policies.WrappingFactory):
289 """Wrap protocols with logging wrappers."""
291 protocol = LoggingProtocol
294 def buildProtocol(self, addr):
295 p = self.protocol(self, self.wrappedFactory.buildProtocol(addr))
296 p.logging = self.logging
300 r = "wrapped " + repr(self.wrappedFactory)
307 """Display log of network traffic."""
309 def __init__(self, p):
313 vals.append(p.inLog[0][0])
315 vals.append(p.outLog[0][0])
316 self.startTime = min(vals)
318 self.xml = x = gtk.glade.XML(sibpath(__file__, "logview.glade"))
319 self.xml.signal_autoconnect(self)
320 self.loglist = self.xml.get_widget("loglist")
321 # setup model, connect it to my treeview
322 self.model = gtk.ListStore(str, str, str)
323 self.loglist.set_model(self.model)
324 self.loglist.set_reorderable(1)
325 self.loglist.set_headers_clickable(1)
326 # self.servers.set_headers_draggable(1)
329 gtk.TreeViewColumn('Time',
330 gtk.CellRendererText(),
332 gtk.TreeViewColumn('D',
333 gtk.CellRendererText(),
335 gtk.TreeViewColumn('Data',
336 gtk.CellRendererText(),
338 self.loglist.append_column(col)
341 for t, data in p.inLog:
342 r.append(((str(t - self.startTime), "R", repr(data)[1:-1])))
343 for t, data in p.outLog:
344 r.append(((str(t - self.startTime), "S", repr(data)[1:-1])))
349 def updateIn(self, (time, data)):
350 self.model.append((str(time - self.startTime), "R", repr(data)[1:-1]))
352 def updateOut(self, (time, data)):
353 self.model.append((str(time - self.startTime), "S", repr(data)[1:-1]))
355 def on_logview_destroy(self, w):
356 self.p.logViewer = None
365 if __name__ == '__main__':
367 log.startLogging(sys.stdout)