OLD | NEW |
| (Empty) |
1 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
2 # See LICENSE for details. | |
3 | |
4 | |
5 """ | |
6 A modified gtk2 reactor with a Glade dialog in-process that allows you to stop, | |
7 suspend, resume and inspect transports interactively. | |
8 """ | |
9 | |
10 __all__ = ['install'] | |
11 | |
12 # Twisted Imports | |
13 from twisted.python import log, threadable, runtime, failure, util, reflect | |
14 from twisted.internet.gtk2reactor import Gtk2Reactor as sup | |
15 | |
16 import gtk | |
17 import gobject | |
18 import gtk.glade | |
19 | |
20 COLUMN_DESCRIPTION = 0 | |
21 COLUMN_TRANSPORT = 1 | |
22 COLUMN_READING = 2 | |
23 COLUMN_WRITING = 3 | |
24 | |
25 | |
26 class GladeReactor(sup): | |
27 """GTK+-2 event loop reactor with GUI. | |
28 """ | |
29 | |
30 def listenTCP(self, port, factory, backlog=50, interface=''): | |
31 from _inspectro import LoggingFactory | |
32 factory = LoggingFactory(factory) | |
33 return sup.listenTCP(self, port, factory, backlog, interface) | |
34 | |
35 def connectTCP(self, host, port, factory, timeout=30, bindAddress=None): | |
36 from _inspectro import LoggingFactory | |
37 factory = LoggingFactory(factory) | |
38 return sup.connectTCP(self, host, port, factory, timeout, bindAddress) | |
39 | |
40 def listenSSL(self, port, factory, contextFactory, backlog=50, interface='')
: | |
41 from _inspectro import LoggingFactory | |
42 factory = LoggingFactory(factory) | |
43 return sup.listenSSL(self, port, factory, contextFactory, backlog, inter
face) | |
44 | |
45 def connectSSL(self, host, port, factory, contextFactory, timeout=30, bindAd
dress=None): | |
46 from _inspectro import LoggingFactory | |
47 factory = LoggingFactory(factory) | |
48 return sup.connectSSL(self, host, port, factory, contextFactory, timeout
, bindAddress) | |
49 | |
50 def connectUNIX(self, address, factory, timeout=30): | |
51 from _inspectro import LoggingFactory | |
52 factory = LoggingFactory(factory) | |
53 return sup.connectUNIX(self, address, factory, timeout) | |
54 | |
55 def listenUNIX(self, address, factory, backlog=50, mode=0666): | |
56 from _inspectro import LoggingFactory | |
57 factory = LoggingFactory(factory) | |
58 return sup.listenUNIX(self, address, factory, backlog, mode) | |
59 | |
60 def on_disconnect_clicked(self, w): | |
61 store, iter = self.servers.get_selection().get_selected() | |
62 store[iter][COLUMN_TRANSPORT].loseConnection() | |
63 | |
64 def on_viewlog_clicked(self, w): | |
65 store, iter = self.servers.get_selection().get_selected() | |
66 data = store[iter][1] | |
67 from _inspectro import LogViewer | |
68 if hasattr(data, "protocol") and not data.protocol.logViewer: | |
69 LogViewer(data.protocol) | |
70 | |
71 def on_inspect_clicked(self, w): | |
72 store, iter = self.servers.get_selection().get_selected() | |
73 data = store[iter] | |
74 from _inspectro import Inspectro | |
75 Inspectro(data[1]) | |
76 | |
77 def on_suspend_clicked(self, w): | |
78 store, iter = self.servers.get_selection().get_selected() | |
79 data = store[iter] | |
80 sup.removeReader(self, data[1]) | |
81 sup.removeWriter(self, data[1]) | |
82 if data[COLUMN_DESCRIPTION].endswith('(suspended)'): | |
83 if data[COLUMN_READING]: | |
84 sup.addReader(self, data[COLUMN_TRANSPORT]) | |
85 if data[COLUMN_WRITING]: | |
86 sup.addWriter(self, data[COLUMN_TRANSPORT]) | |
87 data[COLUMN_DESCRIPTION] = str(data[COLUMN_TRANSPORT]) | |
88 self.toggle_suspend(1) | |
89 else: | |
90 data[0] += ' (suspended)' | |
91 self.toggle_suspend(0) | |
92 | |
93 def toggle_suspend(self, suspending=0): | |
94 stock, nonstock = [('gtk-redo', 'Resume'), | |
95 ('gtk-undo', 'Suspend')][suspending] | |
96 b = self.xml.get_widget("suspend") | |
97 b.set_use_stock(1) | |
98 b.set_label(stock) | |
99 b.get_child().get_child().get_children()[1].set_label(nonstock) | |
100 | |
101 def servers_selection_changed(self, w): | |
102 store, iter = w.get_selected() | |
103 if iter is None: | |
104 self.xml.get_widget("suspend").set_sensitive(0) | |
105 self.xml.get_widget('disconnect').set_sensitive(0) | |
106 else: | |
107 data = store[iter] | |
108 self.toggle_suspend(not | |
109 data[COLUMN_DESCRIPTION].endswith('(suspended)')) | |
110 self.xml.get_widget("suspend").set_sensitive(1) | |
111 self.xml.get_widget('disconnect').set_sensitive(1) | |
112 | |
113 def on_quit_clicked(self, w): | |
114 self.stop() | |
115 | |
116 def __init__(self): | |
117 self.xml = gtk.glade.XML(util.sibpath(__file__,"gladereactor.glade")) | |
118 d = {} | |
119 for m in reflect.prefixedMethods(self, "on_"): | |
120 d[m.im_func.__name__] = m | |
121 self.xml.signal_autoconnect(d) | |
122 self.xml.get_widget('window1').connect('destroy', | |
123 lambda w: self.stop()) | |
124 self.servers = self.xml.get_widget("servertree") | |
125 sel = self.servers.get_selection() | |
126 sel.set_mode(gtk.SELECTION_SINGLE) | |
127 sel.connect("changed", | |
128 self.servers_selection_changed) | |
129 ## argh coredump: self.servers_selection_changed(sel) | |
130 self.xml.get_widget('suspend').set_sensitive(0) | |
131 self.xml.get_widget('disconnect').set_sensitive(0) | |
132 # setup model, connect it to my treeview | |
133 self.model = gtk.ListStore(str, object, gobject.TYPE_BOOLEAN, | |
134 gobject.TYPE_BOOLEAN) | |
135 self.servers.set_model(self.model) | |
136 self.servers.set_reorderable(1) | |
137 self.servers.set_headers_clickable(1) | |
138 # self.servers.set_headers_draggable(1) | |
139 # add a column | |
140 for col in [ | |
141 gtk.TreeViewColumn('Server', | |
142 gtk.CellRendererText(), | |
143 text=0), | |
144 gtk.TreeViewColumn('Reading', | |
145 gtk.CellRendererToggle(), | |
146 active=2), | |
147 gtk.TreeViewColumn('Writing', | |
148 gtk.CellRendererToggle(), | |
149 active=3)]: | |
150 | |
151 self.servers.append_column(col) | |
152 col.set_resizable(1) | |
153 sup.__init__(self) | |
154 | |
155 def addReader(self, reader): | |
156 sup.addReader(self, reader) | |
157 ## gtk docs suggest this - but it's stupid | |
158 ## self.model.set(self.model.append(), | |
159 ## 0, str(reader), | |
160 ## 1, reader) | |
161 self._maybeAddServer(reader, read=1) | |
162 | |
163 def _goAway(self,reader): | |
164 for p in range(len(self.model)): | |
165 if self.model[p][1] == reader: | |
166 self.model.remove(self.model.get_iter_from_string(str(p))) | |
167 return | |
168 | |
169 | |
170 def _maybeAddServer(self, reader, read=0, write=0): | |
171 p = 0 | |
172 for x in self.model: | |
173 if x[1] == reader: | |
174 if reader == 0: | |
175 reader += 1 | |
176 x[2] += read | |
177 x[3] += write | |
178 x[2] = max(x[2],0) | |
179 x[3] = max(x[3],0) | |
180 | |
181 if not (x[2] or x[3]): | |
182 x[0] = x[0] + '(disconnected)' | |
183 self.callLater(5, self._goAway, reader) | |
184 return | |
185 p += 1 | |
186 else: | |
187 read = max(read,0) | |
188 write = max(write, 0) | |
189 if read or write: | |
190 self.model.append((reader,reader,read,write)) | |
191 | |
192 def addWriter(self, writer): | |
193 sup.addWriter(self, writer) | |
194 self._maybeAddServer(writer, write=1) | |
195 | |
196 def removeReader(self, reader): | |
197 sup.removeReader(self, reader) | |
198 self._maybeAddServer(reader, read=-1) | |
199 | |
200 def removeWriter(self, writer): | |
201 sup.removeWriter(self, writer) | |
202 self._maybeAddServer(writer, write=-1) | |
203 | |
204 def crash(self): | |
205 gtk.main_quit() | |
206 | |
207 def run(self, installSignalHandlers=1): | |
208 self.startRunning(installSignalHandlers=installSignalHandlers) | |
209 self.simulate() | |
210 gtk.main() | |
211 | |
212 | |
213 def install(): | |
214 """Configure the twisted mainloop to be run inside the gtk mainloop. | |
215 """ | |
216 reactor = GladeReactor() | |
217 from twisted.internet.main import installReactor | |
218 installReactor(reactor) | |
219 return reactor | |
OLD | NEW |