Create a new class Signalman which is used to track the glib signals on a widget since at least two of our classes were doing this themselves. Also integrated it into one of those classes, Container() where it is only used by VPaned and HPaned. Also add doctests for it

This commit is contained in:
Chris Jones 2010-01-18 13:17:35 +00:00
parent 8c7218121f
commit 8ad7ac07b1
6 changed files with 123 additions and 29 deletions

View File

@ -10,6 +10,7 @@ from factory import Factory
from config import Config
from util import dbg, err
from translation import _
from signalman import Signalman
# pylint: disable-msg=R0921
class Container(object):
@ -20,13 +21,13 @@ class Container(object):
children = None
config = None
signals = None
cnxids = None
signalman = None
def __init__(self):
"""Class initialiser"""
self.children = []
self.signals = []
self.cnxids = {}
self.cnxids = Signalman()
self.config = Config()
def register_signals(self, widget):
@ -49,28 +50,14 @@ class Container(object):
err('Container:: registering signal for %s on %s failed' %
(signal['name'], widget))
def connect_child(self, widget, signal, handler, data=None):
def connect_child(self, widget, signal, handler, *args):
"""Register the requested signal and record its connection ID"""
if not self.cnxids.has_key(widget):
self.cnxids[widget] = []
if data is not None:
self.cnxids[widget].append(widget.connect(signal, handler, data))
dbg('Container::connect_child: connecting %s(%s) for %s::%s' %
(handler.__name__, data, widget.__class__.__name__, signal))
else:
self.cnxids[widget].append(widget.connect(signal, handler))
dbg('Container::connect_child: registering %s to handle %s::%s' %
(handler.__name__, widget.__class__.__name__, signal))
self.cnxids.new(widget, signal, handler, *args)
return
def disconnect_child(self, widget):
"""De-register the signals for a child"""
if self.cnxids.has_key(widget):
for cnxid in self.cnxids[widget]:
dbg('Container::disconnect_child: removing handler on %s' %
type(widget))
widget.disconnect(cnxid)
del(self.cnxids[widget])
self.cnxids.remove_widget(widget)
def get_offspring(self):
"""Return a list of child widgets, if any"""

View File

@ -37,8 +37,7 @@ class Paned(Container):
dbg("Paned::set_initial_position: Setting position to: %d" % position)
self.set_position(position)
self.disconnect(self.cnxids['init'])
del(self.cnxids['init'])
self.cnxids.remove_signal(self, 'expose-event')
# pylint: disable-msg=W0613
def split_axis(self, widget, vertical=True, sibling=None):
@ -78,7 +77,6 @@ class Paned(Container):
else:
raise ValueError('Paned widgets can only have two children')
self.cnxids[widget] = []
if maker.isinstance(widget, 'Terminal'):
top_window = get_top_window(self)
@ -92,8 +90,7 @@ class Paned(Container):
for signal in signals:
self.connect_child(widget, signal, signals[signal])
self.connect_child(widget, 'maximise', top_window.zoom,
False)
self.connect_child(widget, 'maximise', top_window.zoom, False)
widget.grab_focus()
@ -176,8 +173,7 @@ class HPaned(Paned, gtk.HPaned):
Paned.__init__(self)
gtk.HPaned.__init__(self)
self.register_signals(HPaned)
self.cnxids['init'] = self.connect('expose-event',
self.set_initial_position)
self.cnxids.new(self, 'expose-event', self.set_initial_position)
class VPaned(Paned, gtk.VPaned):
"""Merge gtk.VPaned into our base Paned Container"""
@ -186,8 +182,7 @@ class VPaned(Paned, gtk.VPaned):
Paned.__init__(self)
gtk.VPaned.__init__(self)
self.register_signals(VPaned)
self.cnxids['init'] = self.connect('expose-event',
self.set_initial_position)
self.cnxids.new(self, 'expose-event', self.set_initial_position)
gobject.type_register(HPaned)
gobject.type_register(VPaned)

54
terminatorlib/signalman.py Executable file
View File

@ -0,0 +1,54 @@
#!/usr/bin/python
# Terminator by Chris Jones <cmsj@tenshu.net>
# GPL v2 only
"""signalman.py - class providing a glib signal tracker"""
from util import dbg, err
class Signalman(object):
"""Class providing glib signal tracking and management"""
cnxids = None
def __init__(self):
"""Class initialiser"""
self.cnxids = {}
def __del__(self):
"""Class destructor"""
if len(self.cnxids.keys()) > 0:
err('Signals remain. This is likely a bug: %s' % self.cnxids)
def new(self, widget, signal, handler, *args):
"""Register a new signal on a widget"""
if not self.cnxids.has_key(widget):
dbg('creating new bucket for %s' % type(widget))
self.cnxids[widget] = {}
if self.cnxids[widget].has_key(signal):
err('%s already has a handler for %s' % (id(widget), signal))
self.cnxids[widget][signal] = widget.connect(signal, handler, *args)
dbg('connected %s::%s to %s' % (type(widget), signal, handler))
def remove_signal(self, widget, signal):
"""Remove a signal handler"""
if not self.cnxids[widget].has_key(signal):
err('%s not registered for %s' % (signal, type(widget)))
return
dbg('removing %s::%s' % (type(widget), signal))
widget.disconnect(self.cnxids[widget][signal])
del(self.cnxids[widget][signal])
if len(self.cnxids[widget].keys()) == 0:
dbg('no more signals for widget')
del(self.cnxids[widget])
def remove_widget(self, widget):
"""Remove all signal handlers for a widget"""
if not self.cnxids.has_key(widget):
dbg('%s not registered' % widget)
return
signals = self.cnxids[widget].keys()
for signal in signals:
self.remove_signal(widget, signal)

View File

@ -97,6 +97,7 @@ class Terminal(gtk.VBox):
self.connect('focus-in', self.terminator.focus_changed)
self.matches = {}
# FIXME: Port cnxids to using Signalman
self.cnxids = {}
self.config = Config()

View File

@ -11,6 +11,7 @@ def test_suite():
'cwd',
'factory',
'util',
'testsignalman',
):
suite.addTest(DocTestSuite('terminatorlib.' + name))
return suite

56
terminatorlib/testsignalman.py Executable file
View File

@ -0,0 +1,56 @@
#!/usr/bin/python
# Terminator by Chris Jones <cmsj@tenshu.net>
# GPL v2 only
"""testsignalman.py - Test the signalman class
>>> widget = TestWidget()
>>> signalman = Signalman()
>>> signalman.new(widget, 'test1', handler)
>>> signalman.cnxids[widget].keys()
['test1']
>>> widget.signals.values()
['test1']
>>> signalman.remove_widget(widget)
>>> signalman.cnxids.has_key(widget)
False
>>> widget.signals.values()
[]
>>> signalman.new(widget, 'test2', handler)
>>> signalman.new(widget, 'test3', handler)
>>> signalman.remove_signal(widget, 'test2')
>>> signalman.cnxids[widget].keys()
['test3']
>>> widget.signals.values()
['test3']
>>> signalman.remove_widget(widget)
>>>
"""
from signalman import Signalman
class TestWidget():
signals = None
count = None
def __init__(self):
self.signals = {}
self.count = 0
def connect(self, signal, handler, *args):
self.count = self.count + 1
self.signals[self.count] = signal
return(self.count)
def disconnect(self, signalid):
del(self.signals[signalid])
def handler():
print "I am a test handler"
if __name__ == '__main__':
import sys
import doctest
(failed, attempted) = doctest.testmod()
print "%d/%d tests failed" % (failed, attempted)
sys.exit(failed)