new profile carousel implementation reacts to new profiles

This commit is contained in:
Jakob Ketterl 2021-03-05 18:57:09 +01:00
parent a3cfde02c4
commit 2ba2ec38e0
3 changed files with 50 additions and 15 deletions

View File

@ -351,6 +351,12 @@ class PropertyCarousel(PropertyDelegator):
def addLayer(self, key, value): def addLayer(self, key, value):
self.layers[key] = value self.layers[key] = value
def hasLayer(self, key):
return key in self.layers
def removeLayer(self, key):
del self.layers[key]
def switch(self, key): def switch(self, key):
before = self.pm before = self.pm
self.subscription.cancel() self.subscription.cancel()

View File

@ -10,7 +10,7 @@ import pkgutil
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from owrx.command import CommandMapper from owrx.command import CommandMapper
from owrx.socket import getAvailablePort from owrx.socket import getAvailablePort
from owrx.property import PropertyStack, PropertyLayer, PropertyFilter, PropertyCarousel from owrx.property import PropertyStack, PropertyLayer, PropertyFilter, PropertyCarousel, PropertyDeleted
from owrx.property.filter import ByLambda from owrx.property.filter import ByLambda
from owrx.form import Input, TextInput, NumberInput, CheckboxInput, ModesInput, ExponentialInput from owrx.form import Input, TextInput, NumberInput, CheckboxInput, ModesInput, ExponentialInput
from owrx.form.converter import OptionalConverter from owrx.form.converter import OptionalConverter
@ -61,6 +61,28 @@ class SdrSourceEventClient(ABC):
return SdrClientClass.INACTIVE return SdrClientClass.INACTIVE
class SdrProfileCarousel(PropertyCarousel):
def __init__(self, props):
super().__init__()
for profile_id, profile in props["profiles"].items():
self.addLayer(profile_id, profile)
props["profiles"].wire(self.handleProfileUpdate)
def addLayer(self, profile_id, profile):
profile_stack = PropertyStack()
profile_stack.addLayer(0, PropertyLayer(profile_id=profile_id).readonly())
profile_stack.addLayer(1, profile)
super().addLayer(profile_id, profile_stack)
def handleProfileUpdate(self, changes):
for profile_id, profile in changes.items():
if profile is PropertyDeleted:
self.removeLayer(profile_id)
elif not self.hasLayer(profile_id):
self.addLayer(profile_id, profile)
class SdrSource(ABC): class SdrSource(ABC):
def __init__(self, id, props): def __init__(self, id, props):
self.id = id self.id = id
@ -70,28 +92,19 @@ class SdrSource(ABC):
self.props = PropertyStack() self.props = PropertyStack()
# layer 0 reserved for profile properties # layer 0 reserved for profile properties
self.profileCarousel = PropertyCarousel() self.profileCarousel = SdrProfileCarousel(props)
if "profiles" in props: # prevent profile names from overriding the device name
for profile_id, profile in props["profiles"].items():
profile_stack = PropertyStack()
profile_stack.addLayer(0, PropertyLayer(profile_id=profile_id).readonly())
profile_stack.addLayer(1, profile)
self.profileCarousel.addLayer(profile_id, profile_stack)
self.props.addLayer(0, PropertyFilter(self.profileCarousel, ByLambda(lambda x: x != "name"))) self.props.addLayer(0, PropertyFilter(self.profileCarousel, ByLambda(lambda x: x != "name")))
# layer for runtime writeable properties
# these may be set during runtime, but should not be persisted to disk with the configuration
self.props.addLayer(1, PropertyLayer().filter("profile_id"))
# props from our device config # props from our device config
self.props.addLayer(2, props) self.props.addLayer(1, props)
# the sdr_id is constant, so we put it in a separate layer # the sdr_id is constant, so we put it in a separate layer
# this is used to detect device changes, that are then sent to the client # this is used to detect device changes, that are then sent to the client
self.props.addLayer(3, PropertyLayer(sdr_id=id).readonly()) self.props.addLayer(2, PropertyLayer(sdr_id=id).readonly())
# finally, accept global config properties from the top-level config # finally, accept global config properties from the top-level config
self.props.addLayer(4, Config.get()) self.props.addLayer(3, Config.get())
self.sdrProps = self.props.filter(*self.getEventNames()) self.sdrProps = self.props.filter(*self.getEventNames())

View File

@ -76,3 +76,19 @@ class PropertyCarouselTest(TestCase):
pc = PropertyCarousel() pc = PropertyCarousel()
with self.assertRaises(KeyError): with self.assertRaises(KeyError):
pc.switch("doesntmatter") pc.switch("doesntmatter")
def testHasLayer(self):
pc = PropertyCarousel()
pc.addLayer("testkey", PropertyLayer())
self.assertTrue(pc.hasLayer("testkey"))
self.assertFalse(pc.hasLayer("otherkey"))
def testRemoveLayer(self):
pc = PropertyCarousel()
pl = PropertyLayer(testkey="testvalue")
pc.addLayer("x", pl)
pc.switch("x")
self.assertEqual(pc["testkey"], "testvalue")
pc.removeLayer("x")
with self.assertRaises(KeyError):
pc.switch("x")