+class ConfigPIN(ConfigInteger):
+ def __init__(self, default, len = 4, censor = ""):
+ assert isinstance(default, int), "ConfigPIN default must be an integer"
+ if default == -1:
+ default = "aaaa"
+ ConfigSequence.__init__(self, seperator = ":", limits = [(0, (10**len)-1)], censor_char = censor, default = default)
+ self.len = len
+
+ def getLength(self):
+ return self.len
+
+class ConfigFloat(ConfigSequence):
+ def __init__(self, default, limits):
+ ConfigSequence.__init__(self, seperator = ".", limits = limits, default = default)
+
+ def getFloat(self):
+ return float(self.value[1] / float(self.limits[1][1] + 1) + self.value[0])
+
+ float = property(getFloat)
+
+# an editable text...
+class ConfigText(ConfigElement, NumericalTextInput):
+ def __init__(self, default = "", fixed_size = True):
+ ConfigElement.__init__(self)
+ NumericalTextInput.__init__(self, nextFunc = self.nextFunc, handleTimeout = False)
+
+ self.marked_pos = 0
+ self.fixed_size = fixed_size
+
+ self.value = self.default = default
+
+ def validateMarker(self):
+ if self.marked_pos >= len(self.text):
+ self.marked_pos = len(self.text) - 1
+ if self.marked_pos < 0:
+ self.marked_pos = 0
+
+ #def nextEntry(self):
+ # self.vals[1](self.getConfigPath())
+
+ def handleKey(self, key):
+ # this will no change anything on the value itself
+ # so we can handle it here in gui element
+ if key == KEY_DELETE:
+ self.text = self.text[0:self.marked_pos] + self.text[self.marked_pos + 1:]
+ elif key == KEY_LEFT:
+ self.marked_pos -= 1
+ elif key == KEY_RIGHT:
+ self.marked_pos += 1
+ self.maybeExpand()
+ elif key in KEY_NUMBERS:
+ number = self.getKey(getKeyNumber(key))
+ self.text = self.text[0:self.marked_pos] + unicode(number) + self.text[self.marked_pos + 1:]
+ elif key == KEY_TIMEOUT:
+ self.timeout()
+ return
+
+ self.validateMarker()
+ self.changed()
+
+ def maybeExpand(self):
+ if not self.fixed_size:
+ if self.marked_pos >= len(self.text):
+ self.text = self.text.ljust(len(self.text) + 1)
+
+ def nextFunc(self):
+ self.marked_pos += 1
+ self.maybeExpand()
+ self.validateMarker()
+ self.changed()
+
+ def getValue(self):
+ return self.text.encode("utf-8")
+
+ def setValue(self, val):
+ try:
+ self.text = val.decode("utf-8")
+ except UnicodeDecodeError:
+ self.text = val
+ print "Broken UTF8!"
+
+ value = property(getValue, setValue)
+ _value = property(getValue, setValue)
+
+ def getText(self):
+ return self.value
+
+ def getMulti(self, selected):
+ return ("mtext"[1-selected:], self.value, [self.marked_pos])
+
+ def helpWindow(self):
+ from Screens.NumericalTextInputHelpDialog import NumericalTextInputHelpDialog
+ return (NumericalTextInputHelpDialog,self)
+
+ def getHTML(self, id):
+ return '<input type="text" name="' + id + '" value="' + self.value + '" /><br>\n'
+
+ def unsafeAssign(self, value):
+ self.value = str(value)
+
+# a slider.
+class ConfigSlider(ConfigElement):
+ def __init__(self, default = 0, increment = 1, limits = (0, 100)):
+ ConfigElement.__init__(self)
+ self.value = self.default = default
+ self.min = limits[0]
+ self.max = limits[1]
+ self.increment = increment
+
+ def checkValues(self):
+ if self.value < self.min:
+ self.value = self.min
+
+ if self.value > self.max:
+ self.value = self.max
+
+ def handleKey(self, key):
+ if key == KEY_LEFT:
+ self.value -= self.increment
+ elif key == KEY_RIGHT:
+ self.value += self.increment
+ else:
+ return
+
+ self.checkValues()
+ self.changed()
+
+ def getText(self):
+ return "%d / %d" % (self.value, self.max)
+
+ def getMulti(self, selected):
+ self.checkValues()
+ return ("slider", self.value, self.max)
+
+ def fromstring(self, value):
+ return int(value)
+
+# a satlist. in fact, it's a ConfigSelection.
+class ConfigSatlist(ConfigSelection):
+ def __init__(self, list, default = None):
+ if default is not None:
+ default = str(default)
+ ConfigSelection.__init__(self, choices = [(str(orbpos), desc) for (orbpos, desc) in list], default = default)
+
+ def getOrbitalPosition(self):
+ if self.value == "":
+ return None
+ return int(self.value)
+
+ orbital_position = property(getOrbitalPosition)
+
+# nothing.
+class ConfigNothing(ConfigSelection):
+ def __init__(self):
+ ConfigSelection.__init__(self, choices = [""])
+
+# until here, 'saved_value' always had to be a *string*.
+# now, in ConfigSubsection, and only there, saved_value
+# is a dict, essentially forming a tree.
+#
+# config.foo.bar=True
+# config.foobar=False
+#
+# turns into:
+# config.saved_value == {"foo": {"bar": "True"}, "foobar": "False"}
+#
+
+
+class ConfigSubsectionContent(object):
+ pass
+
+# we store a backup of the loaded configuration
+# data in self.stored_values, to be able to deploy
+# them when a new config element will be added,
+# so non-default values are instantly available
+
+# A list, for example:
+# config.dipswitches = ConfigSubList()
+# config.dipswitches.append(ConfigYesNo())
+# config.dipswitches.append(ConfigYesNo())
+# config.dipswitches.append(ConfigYesNo())
+class ConfigSubList(list, object):
+ def __init__(self):
+ object.__init__(self)
+ list.__init__(self)
+ self.stored_values = {}
+
+ def save(self):
+ for x in self:
+ x.save()
+
+ def load(self):
+ for x in self:
+ x.load()
+
+ def getSavedValue(self):
+ res = {}
+ for i in range(len(self)):
+ sv = self[i].saved_value
+ if sv is not None:
+ res[str(i)] = sv
+ return res
+
+ def setSavedValue(self, values):
+ self.stored_values = dict(values)
+ for (key, val) in self.stored_values.items():
+ if int(key) < len(self):
+ self[int(key)].saved_value = val
+
+ saved_value = property(getSavedValue, setSavedValue)
+
+ def append(self, item):
+ i = str(len(self))
+ list.append(self, item)
+ if i in self.stored_values:
+ item.saved_value = self.stored_values[i]
+ item.load()
+
+ def dict(self):
+ res = dict()
+ for index in range(len(self)):
+ res[str(index)] = self[index]
+ return res
+
+# same as ConfigSubList, just as a dictionary.
+# care must be taken that the 'key' has a proper
+# str() method, because it will be used in the config
+# file.
+class ConfigSubDict(dict, object):
+ def __init__(self):
+ object.__init__(self)
+ dict.__init__(self)
+ self.stored_values = {}
+
+ def save(self):
+ for x in self.values():
+ x.save()
+
+ def load(self):
+ for x in self.values():
+ x.load()
+
+ def getSavedValue(self):
+ res = {}
+ for (key, val) in self.items():
+ if val.saved_value is not None:
+ res[str(key)] = val.saved_value
+ return res
+
+ def setSavedValue(self, values):
+ self.stored_values = dict(values)
+ for (key, val) in self.items():
+ if str(key) in self.stored_values:
+ val = self.stored_values[str(key)]
+
+ saved_value = property(getSavedValue, setSavedValue)
+
+ def __setitem__(self, key, item):
+ dict.__setitem__(self, key, item)
+ if str(key) in self.stored_values:
+ item.saved_value = self.stored_values[str(key)]
+ item.load()
+
+ def dict(self):
+ return self
+
+# Like the classes above, just with a more "native"
+# syntax.
+#
+# some evil stuff must be done to allow instant
+# loading of added elements. this is why this class
+# is so complex.
+#
+# we need the 'content' because we overwrite
+# __setattr__.
+# If you don't understand this, try adding
+# __setattr__ to a usual exisiting class and you will.
+class ConfigSubsection(object):
+ def __init__(self):
+ object.__init__(self)
+ self.__dict__["content"] = ConfigSubsectionContent()
+ self.content.items = { }
+ self.content.stored_values = { }
+
+ def __setattr__(self, name, value):
+ if name == "saved_value":
+ return self.setSavedValue(value)
+ assert isinstance(value, ConfigSubsection) or isinstance(value, ConfigElement) or isinstance(value, ConfigSubList) or isinstance(value, ConfigSubDict), "ConfigSubsections can only store ConfigSubsections, ConfigSubLists, ConfigSubDicts or ConfigElements"
+ self.content.items[name] = value
+ if name in self.content.stored_values:
+ #print "ok, now we have a new item,", name, "and have the following value for it:", self.content.stored_values[name]
+ value.saved_value = self.content.stored_values[name]
+ value.load()
+
+ def __getattr__(self, name):
+ return self.content.items[name]
+
+ def getSavedValue(self):
+ res = self.content.stored_values
+ for (key, val) in self.content.items.items():
+ if val.saved_value is not None:
+ res[key] = val.saved_value
+ elif key in res:
+ del res[key]
+
+ return res
+
+ def setSavedValue(self, values):
+ values = dict(values)
+
+ self.content.stored_values = values
+
+ for (key, val) in self.content.items.items():
+ if key in values:
+ val.setSavedValue(values[key])
+
+ saved_value = property(getSavedValue, setSavedValue)
+
+ def save(self):
+ for x in self.content.items.values():
+ x.save()
+
+ def load(self):
+ for x in self.content.items.values():
+ x.load()
+
+ def dict(self):
+ return self.content.items
+
+# the root config object, which also can "pickle" (=serialize)
+# down the whole config tree.
+#
+# we try to keep non-existing config entries, to apply them whenever
+# a new config entry is added to a subsection
+# also, non-existing config entries will be saved, so they won't be
+# lost when a config entry disappears.
+class Config(ConfigSubsection):