openwebrx-clone/owrx/active/list/__init__.py

105 lines
3.2 KiB
Python
Raw Permalink Normal View History

from abc import ABC, abstractmethod
import logging
logger = logging.getLogger(__name__)
2022-12-14 00:07:20 +00:00
class ActiveListChange(ABC):
pass
2022-12-14 00:07:20 +00:00
class ActiveListIndexUpdated(ActiveListChange):
def __init__(self, index: int, oldValue, newValue):
self.index = index
self.oldValue = oldValue
self.newValue = newValue
class ActiveListIndexAppended(ActiveListChange):
def __init__(self, index: int, newValue):
self.index = index
self.newValue = newValue
class ActiveListIndexDeleted(ActiveListChange):
def __init__(self, index: int, oldValue):
self.index = index
self.oldValue = oldValue
class ActiveListListener(ABC):
@abstractmethod
2022-12-14 00:07:20 +00:00
def onListChange(self, changes: list[ActiveListChange]):
pass
2022-12-14 00:22:48 +00:00
class ActiveListTransformationListener(ActiveListListener):
def __init__(self, transformation: callable, target: "ActiveList"):
self.transformation = transformation
self.target = target
def onListChange(self, changes: list[ActiveListChange]):
for change in changes:
if isinstance(change, ActiveListIndexUpdated):
self.target[change.index] = self.transformation(change.newValue)
elif isinstance(change, ActiveListIndexAppended):
self.target.append(self.transformation(change.newValue))
elif isinstance(change, ActiveListIndexDeleted):
del self.target[change.index]
class ActiveList:
def __init__(self, elements: list = None):
self.delegate = elements.copy() if elements is not None else []
self.listeners = []
def addListener(self, listener: ActiveListListener):
if listener in self.listeners:
return
self.listeners.append(listener)
def removeListener(self, listener: ActiveListListener):
if listener not in self.listeners:
return
self.listeners.remove(listener)
def append(self, value):
self.delegate.append(value)
2022-12-14 00:07:20 +00:00
self.__fireChanges([ActiveListIndexAppended(len(self) - 1, value)])
def __fireChanges(self, changes: list[ActiveListChange]):
for listener in self.listeners:
try:
2022-12-14 00:07:20 +00:00
listener.onListChange(changes)
except Exception:
2022-12-14 00:07:20 +00:00
logger.exception("Exception during onListChange notification")
def remove(self, value):
self.__delitem__(self.delegate.index(value))
2022-12-14 00:22:48 +00:00
def map(self, transform: callable):
res = ActiveList([transform(v) for v in self])
self.addListener(ActiveListTransformationListener(transform, res))
return res
def __setitem__(self, key, value):
2022-12-14 00:07:20 +00:00
if self.delegate[key] == value:
return
oldValue = self.delegate[key]
self.delegate[key] = value
2022-12-14 00:07:20 +00:00
self.__fireChanges([ActiveListIndexUpdated(key, oldValue, value)])
def __delitem__(self, key):
2022-12-14 00:07:20 +00:00
oldValue = self.delegate[key]
del self.delegate[key]
2022-12-14 00:07:20 +00:00
self.__fireChanges([ActiveListIndexDeleted(key, oldValue)])
def __getitem__(self, key):
return self.delegate[key]
def __len__(self):
return len(self.delegate)
def __iter__(self):
return self.delegate.__iter__()