g13gui: Make observers capable of subscribing to keys

This reduces some of the notifications during changes by reducing the scope of
changes that are monitored by other components in the system. IOW, this allows
keys to only care about their particular changes, rather than all key binding
changes in a BindingProfile.
This commit is contained in:
June Tate-Gans 2021-04-27 18:02:24 -05:00
parent 3183ae8b2b
commit 8f46071239
2 changed files with 29 additions and 11 deletions

View File

@ -12,8 +12,6 @@ class ChangeType(Enum):
class Observer(object): class Observer(object):
"""Simple interface class to handle Observer-style notifications"""
def onSubjectChanged(self, subject, changeType, key, data=None): def onSubjectChanged(self, subject, changeType, key, data=None):
"""Event handler for observer notifications. """Event handler for observer notifications.
@ -36,18 +34,22 @@ class Observer(object):
class Subject(object): class Subject(object):
"""Simple class to handle the subject-side of the Observer pattern.""" """Simple class to handle the subject-side of the Observer pattern."""
def registerObserver(self, observer): AllKeys = ''
def registerObserver(self, observer, subscribedKeys=AllKeys):
"""Registers an Observer class as an observer of this object""" """Registers an Observer class as an observer of this object"""
if subscribedKeys != Subject.AllKeys:
subscribedKeys = frozenset(subscribedKeys)
if '_observers' not in self.__dict__: if '_observers' not in self.__dict__:
self._observers = {observer} self._observers = {observer: subscribedKeys}
else: else:
self._observers.add(observer) self._observers[observer] = subscribedKeys
def removeObserver(self, observer): def removeObserver(self, observer):
"""Removes an observer from this object""" """Removes an observer from this object"""
if '_observers' in self.__dict__: if '_observers' in self.__dict__:
if observer in self._observers: if observer in self._observers:
self._observers.discard(observer) del self._observers[observer]
def addChange(self, type, key, data=None): def addChange(self, type, key, data=None):
"""Schedules a change notification for transmitting later. """Schedules a change notification for transmitting later.
@ -80,16 +82,17 @@ class Subject(object):
when no observers are registered will still flush the change buffer. when no observers are registered will still flush the change buffer.
""" """
if '_observers' in self.__dict__ and '_changes' in self.__dict__: if '_observers' in self.__dict__ and '_changes' in self.__dict__:
for observer in self._observers: for observer, subscribedKeys in self._observers.items():
for change in self._changes: for type, key, data in self._changes:
observer.onSubjectChanged(self, *change) if subscribedKeys == Subject.AllKeys or key in subscribedKeys:
observer.onSubjectChanged(self, type, key, data)
self._changes = [] self._changes = []
class ObserverTestCase(Observer, unittest.TestCase): class ObserverTestCase(Observer, unittest.TestCase):
def __init__(self, methodName): def __init__(self, methodName):
unittest.TestCase.__init__(self, methodName) unittest.TestCase.__init__(self, methodName)
self.changes = []
self.clearChanges() self.clearChanges()
def onSubjectChanged(self, subject, type, key, data=None): def onSubjectChanged(self, subject, type, key, data=None):

View File

@ -5,7 +5,8 @@ import observer
class TestIncorrectObserver(observer.Observer): class TestIncorrectObserver(observer.Observer):
pass def __hash__(self):
return hash('TestIncorrectObserver')
class TestSubject(observer.Subject): class TestSubject(observer.Subject):
@ -50,6 +51,20 @@ class ObserverTestCase(observer.ObserverTestCase):
self.assertChangeNotified(self.subject, observer.ChangeType.ADD, 'foo') self.assertChangeNotified(self.subject, observer.ChangeType.ADD, 'foo')
self.assertChangeDataEquals('bar') self.assertChangeDataEquals('bar')
def testSubscribedKeys(self):
self.subject.registerObserver(self, {'a', 'b'})
self.subject.addChange(observer.ChangeType.ADD, 'a')
self.subject.addChange(observer.ChangeType.ADD, 'b')
self.subject.addChange(observer.ChangeType.ADD, 'c')
self.subject.notifyChanged()
self.assertChangeCount(2)
self.assertChangeNotified(self.subject, observer.ChangeType.ADD, 'a')
self.nextChange()
self.assertChangeNotified(self.subject, observer.ChangeType.ADD, 'b')
self.nextChange()
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()