# Twisted, the Framework of Your Internet
# Copyright (C) 2001 Matthew W. Lefkowitz
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
A modified gtk2 reactor with a Glade dialog in-process that allows you to stop,
suspend, resume and inspect transports interactively.
"""
__all__ = ['install']
# Twisted Imports
from twisted.python import log, threadable, runtime, failure, util, reflect, components
from twisted.internet.gtk2reactor import Gtk2Reactor as sup
import gtk
import gobject
import gtk.glade
COLUMN_DESCRIPTION = 0
COLUMN_TRANSPORT = 1
COLUMN_READING = 2
COLUMN_WRITING = 3
class GladeReactor(sup):
"""GTK+-2 event loop reactor with GUI.
"""
def listenTCP(self, port, factory, backlog=5, interface=''):
from _inspectro import LoggingFactory
factory = LoggingFactory(factory)
return sup.listenTCP(self, port, factory, backlog, interface)
def connectTCP(self, host, port, factory, timeout=30, bindAddress=None):
from _inspectro import LoggingFactory
factory = LoggingFactory(factory)
return sup.connectTCP(self, host, port, factory, timeout, bindAddress)
def listenSSL(self, port, factory, contextFactory, backlog=5, interface=''):
from _inspectro import LoggingFactory
factory = LoggingFactory(factory)
return sup.listenSSL(self, port, factory, contextFactory, backlog, interface)
def connectSSL(self, host, port, factory, contextFactory, timeout=30, bindAddress=None):
from _inspectro import LoggingFactory
factory = LoggingFactory(factory)
return sup.connectSSL(self, host, port, factory, contextFactory, timeout, bindAddress)
def connectUNIX(self, address, factory, timeout=30):
from _inspectro import LoggingFactory
factory = LoggingFactory(factory)
return sup.connectUNIX(self, address, factory, timeout)
def listenUNIX(self, address, factory, backlog=5, mode=0666):
from _inspectro import LoggingFactory
factory = LoggingFactory(factory)
return sup.listenUNIX(self, address, factory, backlog, mode)
def on_disconnect_clicked(self, w):
store, iter = self.servers.get_selection().get_selected()
store[iter][COLUMN_TRANSPORT].loseConnection()
def on_viewlog_clicked(self, w):
store, iter = self.servers.get_selection().get_selected()
data = store[iter][1]
from _inspectro import LogViewer
if hasattr(data, "protocol") and not data.protocol.logViewer:
LogViewer(data.protocol)
def on_inspect_clicked(self, w):
store, iter = self.servers.get_selection().get_selected()
data = store[iter]
from _inspectro import Inspectro
Inspectro(data[1])
def on_suspend_clicked(self, w):
store, iter = self.servers.get_selection().get_selected()
data = store[iter]
sup.removeReader(self, data[1])
sup.removeWriter(self, data[1])
if data[COLUMN_DESCRIPTION].endswith('(suspended)'):
if data[COLUMN_READING]:
sup.addReader(self, data[COLUMN_TRANSPORT])
if data[COLUMN_WRITING]:
sup.addWriter(self, data[COLUMN_TRANSPORT])
data[COLUMN_DESCRIPTION] = str(data[COLUMN_TRANSPORT])
self.toggle_suspend(1)
else:
data[0] += ' (suspended)'
self.toggle_suspend(0)
def toggle_suspend(self, suspending=0):
stock, nonstock = [('gtk-redo', 'Resume'),
('gtk-undo', 'Suspend')][suspending]
b = self.xml.get_widget("suspend")
b.set_use_stock(1)
b.set_label(stock)
b.get_child().get_child().get_children()[1].set_label(nonstock)
def servers_selection_changed(self, w):
store, iter = w.get_selected()
if iter is None:
self.xml.get_widget("suspend").set_sensitive(0)
self.xml.get_widget('disconnect').set_sensitive(0)
else:
data = store[iter]
self.toggle_suspend(not
data[COLUMN_DESCRIPTION].endswith('(suspended)'))
self.xml.get_widget("suspend").set_sensitive(1)
self.xml.get_widget('disconnect').set_sensitive(1)
def on_quit_clicked(self, w):
self.stop()
def __init__(self):
self.xml = gtk.glade.XML(util.sibpath(__file__,"gladereactor.glade"))
d = {}
for m in reflect.prefixedMethods(self, "on_"):
d[m.im_func.__name__] = m
self.xml.signal_autoconnect(d)
self.xml.get_widget('window1').connect('destroy',
lambda w: self.stop())
self.servers = self.xml.get_widget("servertree")
sel = self.servers.get_selection()
sel.set_mode(gtk.SELECTION_SINGLE)
sel.connect("changed",
self.servers_selection_changed)
## argh coredump: self.servers_selection_changed(sel)
self.xml.get_widget('suspend').set_sensitive(0)
self.xml.get_widget('disconnect').set_sensitive(0)
# setup model, connect it to my treeview
self.model = gtk.ListStore(str, object, gobject.TYPE_BOOLEAN,
gobject.TYPE_BOOLEAN)
self.servers.set_model(self.model)
self.servers.set_reorderable(1)
self.servers.set_headers_clickable(1)
# self.servers.set_headers_draggable(1)
# add a column
for col in [
gtk.TreeViewColumn('Server',
gtk.CellRendererText(),
text=0),
gtk.TreeViewColumn('Reading',
gtk.CellRendererToggle(),
active=2),
gtk.TreeViewColumn('Writing',
gtk.CellRendererToggle(),
active=3)]:
self.servers.append_column(col)
col.set_resizable(1)
sup.__init__(self)
def addReader(self, reader):
sup.addReader(self, reader)
## gtk docs suggest this - but it's stupid
## self.model.set(self.model.append(),
## 0, str(reader),
## 1, reader)
self._maybeAddServer(reader, read=1)
def _goAway(self,reader):
for p in range(len(self.model)):
if self.model[p][1] == reader:
self.model.remove(self.model.get_iter_from_string(str(p)))
return
def _maybeAddServer(self, reader, read=0, write=0):
p = 0
for x in self.model:
if x[1] == reader:
if reader == 0:
reader += 1
x[2] += read
x[3] += write
x[2] = max(x[2],0)
x[3] = max(x[3],0)
if not (x[2] or x[3]):
x[0] = x[0] + '(disconnected)'
self.callLater(5, self._goAway, reader)
return
p += 1
else:
read = max(read,0)
write = max(write, 0)
if read or write:
self.model.append((reader,reader,read,write))
def addWriter(self, writer):
sup.addWriter(self, writer)
self._maybeAddServer(writer, write=1)
def removeReader(self, reader):
sup.removeReader(self, reader)
self._maybeAddServer(reader, read=-1)
def removeWriter(self, writer):
sup.removeWriter(self, writer)
self._maybeAddServer(writer, write=-1)
def crash(self):
gtk.main_quit()
def run(self, installSignalHandlers=1):
self.startRunning(installSignalHandlers=installSignalHandlers)
self.simulate()
gtk.main()
def install():
"""Configure the twisted mainloop to be run inside the gtk mainloop.
"""
reactor = GladeReactor()
from twisted.internet.main import installReactor
installReactor(reactor)
return reactor
syntax highlighted by Code2HTML, v. 0.9.1