+ if self.save_disabled or self.value == self.default:
+ self.saved_value = None
+ else:
+ self.saved_value = self.tostring(self.value)
+
+ def cancel(self):
+ self.load()
+
+ def isChanged(self):
+ if self.saved_value is None and self.value == self.default:
+ return False
+ return self.tostring(self.value) != self.saved_value
+
+ def changed(self):
+ for x in self.notifiers:
+ x(self)
+
+ def addNotifier(self, notifier, initial_call = True):
+ assert callable(notifier), "notifiers must be callable"
+ self.notifiers.append(notifier)
+
+ # CHECKME:
+ # do we want to call the notifier
+ # - at all when adding it? (yes, though optional)
+ # - when the default is active? (yes)
+ # - when no value *yet* has been set,
+ # because no config has ever been read (currently yes)
+ # (though that's not so easy to detect.
+ # the entry could just be new.)
+ if initial_call:
+ notifier(self)
+
+ def disableSave(self):
+ self.save_disabled = True
+
+ def __call__(self, selected):
+ return self.getMulti(selected)
+
+ def onSelect(self, session):
+ pass
+
+ def onDeselect(self, session):
+ pass
+
+KEY_LEFT = 0
+KEY_RIGHT = 1
+KEY_OK = 2
+KEY_DELETE = 3
+KEY_BACKSPACE = 4
+KEY_HOME = 5
+KEY_END = 6
+KEY_TOGGLEOW = 7
+KEY_ASCII = 8
+KEY_TIMEOUT = 9
+KEY_NUMBERS = range(12, 12+10)
+KEY_0 = 12
+KEY_9 = 12+9
+
+def getKeyNumber(key):
+ assert key in KEY_NUMBERS
+ return key - KEY_0
+
+#
+# ConfigSelection is a "one of.."-type.
+# it has the "choices", usually a list, which contains
+# (id, desc)-tuples (or just only the ids, in case the id
+# will be used as description)
+#
+# all ids MUST be plain strings.
+#
+class ConfigSelection(ConfigElement):
+ def __init__(self, choices, default = None):
+ ConfigElement.__init__(self)
+ self._value = None
+ self.setChoices(choices, default)
+
+ def setChoices(self, choices, default = None):
+ self.choices = []
+ self.description = {}
+
+ if isinstance(choices, list):
+ for x in choices:
+ if isinstance(x, tuple):
+ self.choices.append(x[0])
+ self.description[x[0]] = x[1]
+ else:
+ self.choices.append(x)
+ self.description[x] = x
+ elif isinstance(choices, dict):
+ for (key, val) in choices.items():
+ self.choices.append(key)
+ self.description[key] = val
+ else:
+ assert False, "ConfigSelection choices must be dict or list!"
+
+ #assert len(self.choices), "you can't have an empty configselection"
+ if len(self.choices) == 0:
+ self.choices = [""]
+ self.description[""] = ""
+
+ if default is None:
+ default = self.choices[0]
+
+ assert default in self.choices, "default must be in choice list, but " + repr(default) + " is not!"
+ for x in self.choices:
+ assert isinstance(x, str), "ConfigSelection choices must be strings"
+
+ self.default = default
+
+ if self.value == None or not self.value in self.choices:
+ self.value = default
+
+ def setValue(self, value):
+ if value in self.choices:
+ self._value = value
+ else:
+ self._value = self.default
+
+ self.changed()
+
+ def tostring(self, val):
+ return val
+
+ def getValue(self):
+ return self._value
+
+ def setCurrentText(self, text):
+ i = self.choices.index(self.value)
+ del self.description[self.choices[i]]
+ self.choices[i] = text
+ self.description[text] = text
+ self._value = text
+
+ value = property(getValue, setValue)
+
+ def getIndex(self):
+ return self.choices.index(self.value)
+
+ index = property(getIndex)
+
+ # GUI
+ def handleKey(self, key):
+ nchoices = len(self.choices)
+ i = self.choices.index(self.value)
+ if key == KEY_LEFT:
+ self.value = self.choices[(i + nchoices - 1) % nchoices]
+ elif key == KEY_RIGHT:
+ self.value = self.choices[(i + 1) % nchoices]
+ elif key == KEY_HOME:
+ self.value = self.choices[0]
+ elif key == KEY_END:
+ self.value = self.choices[nchoices - 1]
+
+ def getText(self):
+ descr = self.description[self.value]
+ if len(descr):
+ return _(descr)
+ return descr
+
+ def getMulti(self, selected):
+ descr = self.description[self.value]
+ if len(descr):
+ return ("text", _(descr))
+ return ("text", descr)
+
+ # HTML
+ def getHTML(self, id):
+ res = ""
+ for v in self.choices:
+ if self.value == v:
+ checked = 'checked="checked" '
+ else:
+ checked = ''
+ res += '<input type="radio" name="' + id + '" ' + checked + 'value="' + v + '">' + self.description[v] + "</input></br>\n"
+ return res;
+
+ def unsafeAssign(self, value):
+ # setValue does check if value is in choices. This is safe enough.
+ self.value = value
+
+# a binary decision.
+#
+# several customized versions exist for different
+# descriptions.
+#
+class ConfigBoolean(ConfigElement):
+ def __init__(self, default = False, descriptions = {False: "false", True: "true"}):
+ ConfigElement.__init__(self)
+ self.descriptions = descriptions
+ self.value = self.default = default
+ def handleKey(self, key):
+ if key in [KEY_LEFT, KEY_RIGHT]:
+ self.value = not self.value
+ elif key == KEY_HOME:
+ self.value = False
+ elif key == KEY_END:
+ self.value = True
+
+ def getText(self):
+ descr = self.descriptions[self.value]
+ if len(descr):
+ return _(descr)
+ return descr
+
+ def getMulti(self, selected):
+ descr = self.descriptions[self.value]
+ if len(descr):
+ return ("text", _(descr))
+ return ("text", descr)
+
+ def tostring(self, value):
+ if not value:
+ return "false"
+ else:
+ return "true"
+
+ def fromstring(self, val):
+ if val == "true":
+ return True
+ else:
+ return False
+
+ def getHTML(self, id):
+ if self.value:
+ checked = ' checked="checked"'
+ else:
+ checked = ''
+ return '<input type="checkbox" name="' + id + '" value="1" ' + checked + " />"
+
+ # this is FLAWED. and must be fixed.
+ def unsafeAssign(self, value):
+ if value == "1":
+ self.value = True
+ else:
+ self.value = False
+
+class ConfigYesNo(ConfigBoolean):
+ def __init__(self, default = False):
+ ConfigBoolean.__init__(self, default = default, descriptions = {False: _("no"), True: _("yes")})
+
+class ConfigOnOff(ConfigBoolean):
+ def __init__(self, default = False):
+ ConfigBoolean.__init__(self, default = default, descriptions = {False: _("off"), True: _("on")})
+
+class ConfigEnableDisable(ConfigBoolean):
+ def __init__(self, default = False):
+ ConfigBoolean.__init__(self, default = default, descriptions = {False: _("disable"), True: _("enable")})
+
+class ConfigDateTime(ConfigElement):
+ def __init__(self, default, formatstring, increment = 86400):
+ ConfigElement.__init__(self)
+ self.increment = increment
+ self.formatstring = formatstring
+ self.value = self.default = int(default)
+
+ def handleKey(self, key):
+ if key == KEY_LEFT:
+ self.value = self.value - self.increment
+ elif key == KEY_RIGHT:
+ self.value = self.value + self.increment
+ elif key == KEY_HOME or key == KEY_END:
+ self.value = self.default
+
+ def getText(self):
+ return time.strftime(self.formatstring, time.localtime(self.value))
+
+ def getMulti(self, selected):
+ return ("text", time.strftime(self.formatstring, time.localtime(self.value)))
+
+ def fromstring(self, val):
+ return int(val)
+
+# *THE* mighty config element class
+#
+# allows you to store/edit a sequence of values.
+# can be used for IP-addresses, dates, plain integers, ...
+# several helper exist to ease this up a bit.
+#
+class ConfigSequence(ConfigElement):
+ def __init__(self, seperator, limits, censor_char = "", default = None):
+ ConfigElement.__init__(self)
+ assert isinstance(limits, list) and len(limits[0]) == 2, "limits must be [(min, max),...]-tuple-list"
+ assert censor_char == "" or len(censor_char) == 1, "censor char must be a single char (or \"\")"
+ #assert isinstance(default, list), "default must be a list"
+ #assert isinstance(default[0], int), "list must contain numbers"
+ #assert len(default) == len(limits), "length must match"
+
+ self.marked_pos = 0
+ self.seperator = seperator
+ self.limits = limits
+ self.censor_char = censor_char
+
+ self.default = default
+ self.value = copy.copy(default)
+
+ self.endNotifier = []
+
+ def validate(self):
+ max_pos = 0
+ num = 0
+ for i in self._value:
+ max_pos += len(str(self.limits[num][1]))
+
+ while self._value[num] < self.limits[num][0]:
+ self._value[num] += 1
+
+ while self._value[num] > self.limits[num][1]:
+ self._value[num] -= 1
+
+ num += 1
+
+ if self.marked_pos >= max_pos:
+ for x in self.endNotifier:
+ x(self)
+ self.marked_pos = max_pos - 1
+
+ if self.marked_pos < 0:
+ self.marked_pos = 0
+
+ def validatePos(self):
+ if self.marked_pos < 0:
+ self.marked_pos = 0