2 from enigma import getPrevAsciiCode
3 from Tools.NumericalTextInput import NumericalTextInput
4 from Tools.Directories import resolveFilename, SCOPE_CONFIG
5 from Components.Harddisk import harddiskmanager
9 # ConfigElement, the base class of all ConfigElements.
12 # value the current value, usefully encoded.
13 # usually a property which retrieves _value,
14 # and maybe does some reformatting
15 # _value the value as it's going to be saved in the configfile,
16 # though still in non-string form.
17 # this is the object which is actually worked on.
18 # default the initial value. If _value is equal to default,
19 # it will not be stored in the config file
20 # saved_value is a text representation of _value, stored in the config file
22 # and has (at least) the following methods:
23 # save() stores _value into saved_value,
24 # (or stores 'None' if it should not be stored)
25 # load() loads _value from saved_value, or loads
26 # the default if saved_value is 'None' (default)
29 class ConfigElement(object):
32 self.saved_value = None
33 self.last_value = None
34 self.save_disabled = False
36 self.notifiers_final = []
38 self.callNotifiersOnSaveAndCancel = False
40 # you need to override this to do input validation
41 def setValue(self, value):
48 value = property(getValue, setValue)
50 # you need to override this if self.value is not a string
51 def fromstring(self, value):
54 # you can overide this for fancy default handling
58 self.value = self.default
60 self.value = self.fromstring(sv)
62 def tostring(self, value):
65 # you need to override this if str(self.value) doesn't work
67 if self.save_disabled or self.value == self.default:
68 self.saved_value = None
70 self.saved_value = self.tostring(self.value)
71 if self.callNotifiersOnSaveAndCancel:
76 if self.callNotifiersOnSaveAndCancel:
81 if sv is None and self.value == self.default:
83 return self.tostring(self.value) != sv
86 for x in self.notifiers:
89 def changedFinal(self):
90 for x in self.notifiers_final:
93 def addNotifier(self, notifier, initial_call = True, immediate_feedback = True):
94 assert callable(notifier), "notifiers must be callable"
95 if immediate_feedback:
96 self.notifiers.append(notifier)
98 self.notifiers_final.append(notifier)
100 # do we want to call the notifier
101 # - at all when adding it? (yes, though optional)
102 # - when the default is active? (yes)
103 # - when no value *yet* has been set,
104 # because no config has ever been read (currently yes)
105 # (though that's not so easy to detect.
106 # the entry could just be new.)
110 def disableSave(self):
111 self.save_disabled = True
113 def __call__(self, selected):
114 return self.getMulti(selected)
116 def onSelect(self, session):
119 def onDeselect(self, session):
120 if not self.last_value == self.value:
122 self.last_value = self.value
134 KEY_NUMBERS = range(12, 12+10)
138 def getKeyNumber(key):
139 assert key in KEY_NUMBERS
142 class choicesList(object): # XXX: we might want a better name for this
146 def __init__(self, choices, type = None):
147 self.choices = choices
149 if isinstance(choices, list):
150 self.type = choicesList.LIST_TYPE_LIST
151 elif isinstance(choices, dict):
152 self.type = choicesList.LIST_TYPE_DICT
154 assert False, "choices must be dict or list!"
159 if self.type is choicesList.LIST_TYPE_LIST:
160 ret = [isinstance(x, tuple) and x[0] or x for x in self.choices]
162 ret = self.choices.keys()
166 if self.type is choicesList.LIST_TYPE_LIST:
167 ret = [isinstance(x, tuple) and x[0] or x for x in self.choices]
170 return iter(ret or [""])
173 return len(self.choices) or 1
175 def __getitem__(self, index):
176 if self.type is choicesList.LIST_TYPE_LIST:
177 ret = self.choices[index]
178 if isinstance(ret, tuple):
181 return self.choices.keys()[index]
183 def index(self, value):
184 return self.__list__().index(value)
186 def __setitem__(self, index, value):
187 if self.type is choicesList.LIST_TYPE_LIST:
188 if isinstance(self.choices[index], tuple):
189 self.choices[index] = (value, self.choices[index][1])
191 self.choices[index] = value
193 key = self.choices.keys()[index]
194 orig = self.choices[key]
195 del self.choices[key]
196 self.choices[value] = orig
199 if self.type is choicesList.LIST_TYPE_LIST:
200 default = self.choices[0]
201 if isinstance(default, tuple):
204 default = self.choices.keys()[0]
207 class descriptionList(choicesList): # XXX: we might want a better name for this
209 if self.type is choicesList.LIST_TYPE_LIST:
210 ret = [isinstance(x, tuple) and x[1] or x for x in self.choices]
212 ret = self.choices.values()
216 return iter(self.__list__())
218 def __getitem__(self, index):
219 if self.type is choicesList.LIST_TYPE_LIST:
220 for x in self.choices:
221 if isinstance(x, tuple):
226 return str(index) # Fallback!
228 return str(self.choices.get(index, ""))
230 def __setitem__(self, index, value):
231 if self.type is choicesList.LIST_TYPE_LIST:
232 i = self.index(index)
233 if isinstance(self.choices[i], tuple):
234 self.choices[i] = (self.choices[i][0], value)
236 self.choices[i] = value
238 self.choices[index] = value
241 # ConfigSelection is a "one of.."-type.
242 # it has the "choices", usually a list, which contains
243 # (id, desc)-tuples (or just only the ids, in case the id
244 # will be used as description)
246 # all ids MUST be plain strings.
248 class ConfigSelection(ConfigElement):
249 def __init__(self, choices, default = None):
250 ConfigElement.__init__(self)
252 # this is an exakt copy of def setChoices.. but we save the call overhead
253 self.choices = choicesList(choices)
256 default = self.choices.default()
258 self.default = self._value = self.last_value = default
261 def setChoices(self, choices, default = None):
262 self.choices = choicesList(choices)
265 default = self.choices.default()
267 self.default = self._value = self.last_value = default
270 def setValue(self, value):
271 if value in self.choices:
274 self._value = self.default
277 def tostring(self, val):
283 def setCurrentText(self, text):
284 i = self.choices.index(self.value)
285 self.choices[i] = text
286 descriptionList(self.choices.choices, self.choices.type)[text] = text
289 value = property(getValue, setValue)
292 return self.choices.index(self.value)
294 index = property(getIndex)
297 def handleKey(self, key):
298 nchoices = len(self.choices)
299 i = self.choices.index(self.value)
301 self.value = self.choices[(i + nchoices - 1) % nchoices]
302 elif key == KEY_RIGHT:
303 self.value = self.choices[(i + 1) % nchoices]
304 elif key == KEY_HOME:
305 self.value = self.choices[0]
307 self.value = self.choices[nchoices - 1]
309 def selectNext(self):
310 nchoices = len(self.choices)
311 i = self.choices.index(self.value)
312 self.value = self.choices[(i + 1) % nchoices]
315 descr = descriptionList(self.choices.choices, self.choices.type)[self.value]
320 def getMulti(self, selected):
321 descr = descriptionList(self.choices.choices, self.choices.type)[self.value]
323 return ("text", _(descr))
324 return ("text", descr)
327 def getHTML(self, id):
329 for v in self.choices:
330 descr = descriptionList(self.choices.choices, self.choices.type)[v]
332 checked = 'checked="checked" '
335 res += '<input type="radio" name="' + id + '" ' + checked + 'value="' + v + '">' + descr + "</input></br>\n"
338 def unsafeAssign(self, value):
339 # setValue does check if value is in choices. This is safe enough.
344 # several customized versions exist for different
347 class ConfigBoolean(ConfigElement):
348 def __init__(self, default = False, descriptions = {False: "false", True: "true"}):
349 ConfigElement.__init__(self)
350 self.descriptions = descriptions
351 self.value = self.last_value = self.default = default
353 def handleKey(self, key):
354 if key in [KEY_LEFT, KEY_RIGHT]:
355 self.value = not self.value
356 elif key == KEY_HOME:
362 descr = self.descriptions[self.value]
367 def getMulti(self, selected):
368 descr = self.descriptions[self.value]
370 return ("text", _(descr))
371 return ("text", descr)
373 def tostring(self, value):
379 def fromstring(self, val):
385 def getHTML(self, id):
387 checked = ' checked="checked"'
390 return '<input type="checkbox" name="' + id + '" value="1" ' + checked + " />"
392 # this is FLAWED. and must be fixed.
393 def unsafeAssign(self, value):
399 def onDeselect(self, session):
400 if not self.last_value == self.value:
402 self.last_value = self.value
404 class ConfigYesNo(ConfigBoolean):
405 def __init__(self, default = False):
406 ConfigBoolean.__init__(self, default = default, descriptions = {False: _("no"), True: _("yes")})
408 class ConfigOnOff(ConfigBoolean):
409 def __init__(self, default = False):
410 ConfigBoolean.__init__(self, default = default, descriptions = {False: _("off"), True: _("on")})
412 class ConfigEnableDisable(ConfigBoolean):
413 def __init__(self, default = False):
414 ConfigBoolean.__init__(self, default = default, descriptions = {False: _("disable"), True: _("enable")})
416 class ConfigDateTime(ConfigElement):
417 def __init__(self, default, formatstring, increment = 86400):
418 ConfigElement.__init__(self)
419 self.increment = increment
420 self.formatstring = formatstring
421 self.value = self.last_value = self.default = int(default)
423 def handleKey(self, key):
425 self.value = self.value - self.increment
426 elif key == KEY_RIGHT:
427 self.value = self.value + self.increment
428 elif key == KEY_HOME or key == KEY_END:
429 self.value = self.default
432 return time.strftime(self.formatstring, time.localtime(self.value))
434 def getMulti(self, selected):
435 return ("text", time.strftime(self.formatstring, time.localtime(self.value)))
437 def fromstring(self, val):
440 # *THE* mighty config element class
442 # allows you to store/edit a sequence of values.
443 # can be used for IP-addresses, dates, plain integers, ...
444 # several helper exist to ease this up a bit.
446 class ConfigSequence(ConfigElement):
447 def __init__(self, seperator, limits, censor_char = "", default = None):
448 ConfigElement.__init__(self)
449 assert isinstance(limits, list) and len(limits[0]) == 2, "limits must be [(min, max),...]-tuple-list"
450 assert censor_char == "" or len(censor_char) == 1, "censor char must be a single char (or \"\")"
451 #assert isinstance(default, list), "default must be a list"
452 #assert isinstance(default[0], int), "list must contain numbers"
453 #assert len(default) == len(limits), "length must match"
456 self.seperator = seperator
458 self.censor_char = censor_char
460 self.default = default
461 self.value = copy.copy(default)
462 self.last_value = copy.copy(default)
464 self.endNotifier = []
469 for i in self._value:
470 max_pos += len(str(self.limits[num][1]))
472 if self._value[num] < self.limits[num][0]:
473 self._value[num] = self.limits[num][0]
475 if self._value[num] > self.limits[num][1]:
476 self._value[num] = self.limits[num][1]
480 if self.marked_pos >= max_pos:
481 for x in self.endNotifier:
483 self.marked_pos = max_pos - 1
485 if self.marked_pos < 0:
488 def validatePos(self):
489 if self.marked_pos < 0:
492 total_len = sum([len(str(x[1])) for x in self.limits])
494 if self.marked_pos >= total_len:
495 self.marked_pos = total_len - 1
497 def addEndNotifier(self, notifier):
498 self.endNotifier.append(notifier)
500 def handleKey(self, key):
516 for i in self._value:
517 max_pos += len(str(self.limits[num][1]))
519 self.marked_pos = max_pos - 1
522 if key in KEY_NUMBERS or key == KEY_ASCII:
524 code = getPrevAsciiCode()
525 if code < 48 or code > 57:
529 number = getKeyNumber(key)
532 for x in self.limits:
533 block_len.append(len(str(x[1])))
535 total_len = sum(block_len)
539 block_len_total = [0, ]
541 pos += block_len[blocknumber]
542 block_len_total.append(pos)
543 if pos - 1 >= self.marked_pos:
548 # length of numberblock
549 number_len = len(str(self.limits[blocknumber][1]))
551 # position in the block
552 posinblock = self.marked_pos - block_len_total[blocknumber]
554 oldvalue = self._value[blocknumber]
555 olddec = oldvalue % 10 ** (number_len - posinblock) - (oldvalue % 10 ** (number_len - posinblock - 1))
556 newvalue = oldvalue - olddec + (10 ** (number_len - posinblock - 1) * number)
558 self._value[blocknumber] = newvalue
566 mPos = self.marked_pos
568 for i in self._value:
569 if len(value): #fixme no heading separator possible
570 value += self.seperator
571 if mPos >= len(value) - 1:
574 if self.censor_char == "":
575 value += ("%0" + str(len(str(self.limits[num][1]))) + "d") % i
577 value += (self.censor_char * len(str(self.limits[num][1])))
582 (value, mPos) = self.genText()
585 def getMulti(self, selected):
586 (value, mPos) = self.genText()
587 # only mark cursor when we are selected
588 # (this code is heavily ink optimized!)
590 return ("mtext"[1-selected:], value, [mPos])
592 return ("text", value)
594 def tostring(self, val):
595 return self.seperator.join([self.saveSingle(x) for x in val])
597 def saveSingle(self, v):
600 def fromstring(self, value):
601 return [int(x) for x in value.split(self.seperator)]
603 def onDeselect(self, session):
604 if not self.last_value == self._value:
606 self.last_value = copy.copy(self._value)
608 class ConfigIP(ConfigSequence):
609 def __init__(self, default, auto_jump = False):
610 ConfigSequence.__init__(self, seperator = ".", limits = [(0,255),(0,255),(0,255),(0,255)], default = default)
612 for x in self.limits:
613 self.block_len.append(len(str(x[1])))
614 self.marked_block = 0
615 self.overwrite = True
616 self.auto_jump = auto_jump
618 def handleKey(self, key):
621 if self.marked_block > 0:
622 self.marked_block -= 1
623 self.overwrite = True
626 if self.marked_block < len(self.limits)-1:
627 self.marked_block += 1
628 self.overwrite = True
631 self.marked_block = 0
632 self.overwrite = True
635 self.marked_block = len(self.limits)-1
636 self.overwrite = True
638 if key in KEY_NUMBERS or key == KEY_ASCII:
640 code = getPrevAsciiCode()
641 if code < 48 or code > 57:
645 number = getKeyNumber(key)
646 oldvalue = self._value[self.marked_block]
649 self._value[self.marked_block] = number
650 self.overwrite = False
653 newvalue = oldvalue + number
654 if self.auto_jump and newvalue > self.limits[self.marked_block][1] and self.marked_block < len(self.limits)-1:
655 self.handleKey(KEY_RIGHT)
659 self._value[self.marked_block] = newvalue
661 if len(str(self._value[self.marked_block])) >= self.block_len[self.marked_block]:
662 self.handleKey(KEY_RIGHT)
670 for i in self._value:
671 block_strlen.append(len(str(i)))
673 value += self.seperator
675 leftPos = sum(block_strlen[:(self.marked_block)])+self.marked_block
676 rightPos = sum(block_strlen[:(self.marked_block+1)])+self.marked_block
677 mBlock = range(leftPos, rightPos)
678 return (value, mBlock)
680 def getMulti(self, selected):
681 (value, mBlock) = self.genText()
683 return ("mtext"[1-selected:], value, mBlock)
685 return ("text", value)
687 def getHTML(self, id):
688 # we definitely don't want leading zeros
689 return '.'.join(["%d" % d for d in self.value])
691 class ConfigMAC(ConfigSequence):
692 def __init__(self, default):
693 ConfigSequence.__init__(self, seperator = ":", limits = [(1,255),(1,255),(1,255),(1,255),(1,255),(1,255)], default = default)
695 class ConfigPosition(ConfigSequence):
696 def __init__(self, default, args):
697 ConfigSequence.__init__(self, seperator = ",", limits = [(0,args[0]),(0,args[1]),(0,args[2]),(0,args[3])], default = default)
699 class ConfigClock(ConfigSequence):
700 def __init__(self, default):
702 t = time.localtime(default)
703 ConfigSequence.__init__(self, seperator = ":", limits = [(0,23),(0,59)], default = [t.tm_hour, t.tm_min])
706 # Check if Minutes maxed out
707 if self._value[1] == 59:
708 # Increment Hour, reset Minutes
709 if self._value[0] < 23:
721 # Check if Minutes is minimum
722 if self._value[1] == 0:
723 # Decrement Hour, set Minutes to 59
724 if self._value[0] > 0:
735 class ConfigInteger(ConfigSequence):
736 def __init__(self, default, limits = (0, 9999999999)):
737 ConfigSequence.__init__(self, seperator = ":", limits = [limits], default = default)
739 # you need to override this to do input validation
740 def setValue(self, value):
741 self._value = [value]
745 return self._value[0]
747 value = property(getValue, setValue)
749 def fromstring(self, value):
752 def tostring(self, value):
755 class ConfigPIN(ConfigInteger):
756 def __init__(self, default, len = 4, censor = ""):
757 assert isinstance(default, int), "ConfigPIN default must be an integer"
760 ConfigSequence.__init__(self, seperator = ":", limits = [(0, (10**len)-1)], censor_char = censor, default = default)
766 class ConfigFloat(ConfigSequence):
767 def __init__(self, default, limits):
768 ConfigSequence.__init__(self, seperator = ".", limits = limits, default = default)
771 return float(self.value[1] / float(self.limits[1][1] + 1) + self.value[0])
773 float = property(getFloat)
775 # an editable text...
776 class ConfigText(ConfigElement, NumericalTextInput):
777 def __init__(self, default = "", fixed_size = True, visible_width = False):
778 ConfigElement.__init__(self)
779 NumericalTextInput.__init__(self, nextFunc = self.nextFunc, handleTimeout = False)
782 self.allmarked = (default != "")
783 self.fixed_size = fixed_size
784 self.visible_width = visible_width
786 self.overwrite = fixed_size
787 self.help_window = None
788 self.value = self.last_value = self.default = default
790 def validateMarker(self):
792 if self.marked_pos > len(self.text)-1:
793 self.marked_pos = len(self.text)-1
795 if self.marked_pos > len(self.text):
796 self.marked_pos = len(self.text)
797 if self.marked_pos < 0:
799 if self.visible_width:
800 if self.marked_pos < self.offset:
801 self.offset = self.marked_pos
802 if self.marked_pos >= self.offset + self.visible_width:
803 if self.marked_pos == len(self.text):
804 self.offset = self.marked_pos - self.visible_width
806 self.offset = self.marked_pos - self.visible_width + 1
807 if self.offset > 0 and self.offset + self.visible_width > len(self.text):
808 self.offset = max(0, len(self.text) - self.visible_width)
810 def insertChar(self, ch, pos, owr):
811 if owr or self.overwrite:
812 self.text = self.text[0:pos] + ch + self.text[pos + 1:]
813 elif self.fixed_size:
814 self.text = self.text[0:pos] + ch + self.text[pos:-1]
816 self.text = self.text[0:pos] + ch + self.text[pos:]
818 def deleteChar(self, pos):
819 if not self.fixed_size:
820 self.text = self.text[0:pos] + self.text[pos + 1:]
822 self.text = self.text[0:pos] + " " + self.text[pos + 1:]
824 self.text = self.text[0:pos] + self.text[pos + 1:] + " "
826 def deleteAllChars(self):
828 self.text = " " * len(self.text)
833 def handleKey(self, key):
834 # this will no change anything on the value itself
835 # so we can handle it here in gui element
836 if key == KEY_DELETE:
839 self.deleteAllChars()
840 self.allmarked = False
842 self.deleteChar(self.marked_pos)
843 if self.fixed_size and self.overwrite:
845 elif key == KEY_BACKSPACE:
848 self.deleteAllChars()
849 self.allmarked = False
850 elif self.marked_pos > 0:
851 self.deleteChar(self.marked_pos-1)
852 if not self.fixed_size and self.offset > 0:
855 elif key == KEY_LEFT:
858 self.marked_pos = len(self.text)
859 self.allmarked = False
862 elif key == KEY_RIGHT:
866 self.allmarked = False
869 elif key == KEY_HOME:
871 self.allmarked = False
875 self.allmarked = False
876 self.marked_pos = len(self.text)
877 elif key == KEY_TOGGLEOW:
879 self.overwrite = not self.overwrite
880 elif key == KEY_ASCII:
882 newChar = unichr(getPrevAsciiCode())
884 self.deleteAllChars()
885 self.allmarked = False
886 self.insertChar(newChar, self.marked_pos, False)
888 elif key in KEY_NUMBERS:
889 owr = self.lastKey == getKeyNumber(key)
890 newChar = self.getKey(getKeyNumber(key))
892 self.deleteAllChars()
893 self.allmarked = False
894 self.insertChar(newChar, self.marked_pos, owr)
895 elif key == KEY_TIMEOUT:
898 self.help_window.update(self)
902 self.help_window.update(self)
903 self.validateMarker()
908 self.validateMarker()
912 return self.text.encode("utf-8")
914 def setValue(self, val):
916 self.text = val.decode("utf-8")
917 except UnicodeDecodeError:
918 self.text = val.decode("utf-8", "ignore")
921 value = property(getValue, setValue)
922 _value = property(getValue, setValue)
925 return self.text.encode("utf-8")
927 def getMulti(self, selected):
928 if self.visible_width:
930 mark = range(0, min(self.visible_width, len(self.text)))
932 mark = [self.marked_pos-self.offset]
933 return ("mtext"[1-selected:], self.text[self.offset:self.offset+self.visible_width].encode("utf-8")+" ", mark)
936 mark = range(0, len(self.text))
938 mark = [self.marked_pos]
939 return ("mtext"[1-selected:], self.text.encode("utf-8")+" ", mark)
941 def onSelect(self, session):
942 self.allmarked = (self.value != "")
943 if session is not None:
944 from Screens.NumericalTextInputHelpDialog import NumericalTextInputHelpDialog
945 self.help_window = session.instantiateDialog(NumericalTextInputHelpDialog, self)
946 self.help_window.show()
948 def onDeselect(self, session):
952 session.deleteDialog(self.help_window)
953 self.help_window = None
954 if not self.last_value == self.value:
956 self.last_value = self.value
958 def getHTML(self, id):
959 return '<input type="text" name="' + id + '" value="' + self.value + '" /><br>\n'
961 def unsafeAssign(self, value):
962 self.value = str(value)
964 class ConfigPassword(ConfigText):
965 def __init__(self, default = "", fixed_size = False, visible_width = False, censor = "*"):
966 ConfigText.__init__(self, default = default, fixed_size = fixed_size, visible_width = visible_width)
967 self.censor_char = censor
970 def getMulti(self, selected):
971 mtext, text, mark = ConfigText.getMulti(self, selected)
973 text = len(text) * self.censor_char
974 return (mtext, text, mark)
976 def onSelect(self, session):
977 ConfigText.onSelect(self, session)
980 def onDeselect(self, session):
981 ConfigText.onDeselect(self, session)
984 class ConfigNumber(ConfigText):
985 def __init__(self, default = 0):
986 ConfigText.__init__(self, str(default), fixed_size = False)
989 return int(self.text)
991 def setValue(self, val):
994 value = property(getValue, setValue)
995 _value = property(getValue, setValue)
998 pos = len(self.text) - self.marked_pos
999 self.text = self.text.lstrip("0")
1002 if pos > len(self.text):
1005 self.marked_pos = len(self.text) - pos
1007 def handleKey(self, key):
1008 if key in KEY_NUMBERS or key == KEY_ASCII:
1009 if key == KEY_ASCII:
1010 ascii = getPrevAsciiCode()
1011 if not (48 <= ascii <= 57):
1014 ascii = getKeyNumber(key) + 48
1015 newChar = unichr(ascii)
1017 self.deleteAllChars()
1018 self.allmarked = False
1019 self.insertChar(newChar, self.marked_pos, False)
1020 self.marked_pos += 1
1022 ConfigText.handleKey(self, key)
1025 def onSelect(self, session):
1026 self.allmarked = (self.value != "")
1028 def onDeselect(self, session):
1031 if not self.last_value == self.value:
1033 self.last_value = self.value
1035 class ConfigSearchText(ConfigText):
1036 def __init__(self, default = "", fixed_size = False, visible_width = False):
1037 ConfigText.__init__(self, default = default, fixed_size = fixed_size, visible_width = visible_width)
1038 NumericalTextInput.__init__(self, nextFunc = self.nextFunc, handleTimeout = False, search = True)
1040 class ConfigDirectory(ConfigText):
1041 def __init__(self, default="", visible_width=60):
1042 ConfigText.__init__(self, default, fixed_size = True, visible_width = visible_width)
1043 def handleKey(self, key):
1049 return ConfigText.getValue(self)
1050 def setValue(self, val):
1053 ConfigText.setValue(self, val)
1054 def getMulti(self, selected):
1056 return ("mtext"[1-selected:], _("List of Storage Devices"), range(0))
1058 return ConfigText.getMulti(self, selected)
1061 class ConfigSlider(ConfigElement):
1062 def __init__(self, default = 0, increment = 1, limits = (0, 100)):
1063 ConfigElement.__init__(self)
1064 self.value = self.last_value = self.default = default
1065 self.min = limits[0]
1066 self.max = limits[1]
1067 self.increment = increment
1069 def checkValues(self):
1070 if self.value < self.min:
1071 self.value = self.min
1073 if self.value > self.max:
1074 self.value = self.max
1076 def handleKey(self, key):
1078 self.value -= self.increment
1079 elif key == KEY_RIGHT:
1080 self.value += self.increment
1081 elif key == KEY_HOME:
1082 self.value = self.min
1083 elif key == KEY_END:
1084 self.value = self.max
1090 return "%d / %d" % (self.value, self.max)
1092 def getMulti(self, selected):
1094 return ("slider", self.value, self.max)
1096 def fromstring(self, value):
1099 # a satlist. in fact, it's a ConfigSelection.
1100 class ConfigSatlist(ConfigSelection):
1101 def __init__(self, list, default = None):
1102 if default is not None:
1103 default = str(default)
1104 ConfigSelection.__init__(self, choices = [(str(orbpos), desc) for (orbpos, desc, flags) in list], default = default)
1106 def getOrbitalPosition(self):
1107 if self.value == "":
1109 return int(self.value)
1111 orbital_position = property(getOrbitalPosition)
1113 class ConfigSet(ConfigElement):
1114 def __init__(self, choices, default = []):
1115 ConfigElement.__init__(self)
1116 if isinstance(choices, list):
1118 self.choices = choicesList(choices, choicesList.LIST_TYPE_LIST)
1120 assert False, "ConfigSet choices must be a list!"
1125 self.last_value = self.default = default
1126 self.value = default[:]
1128 def toggleChoice(self, choice):
1129 if choice in self.value:
1130 self.value.remove(choice)
1132 self.value.append(choice)
1136 def handleKey(self, key):
1137 if key in KEY_NUMBERS + [KEY_DELETE, KEY_BACKSPACE]:
1139 self.toggleChoice(self.choices[self.pos])
1140 elif key == KEY_LEFT:
1143 self.pos = len(self.choices)-1
1144 elif key == KEY_RIGHT:
1146 if self.pos >= len(self.choices):
1148 elif key in [KEY_HOME, KEY_END]:
1151 def genString(self, lst):
1153 description = descriptionList(self.choices.choices, choicesList.LIST_TYPE_LIST)
1155 res += description[x]+" "
1159 return self.genString(self.value)
1161 def getMulti(self, selected):
1162 if not selected or self.pos == -1:
1163 return ("text", self.genString(self.value))
1165 description = descriptionList(self.choices.choices, choicesList.LIST_TYPE_LIST)
1167 ch = self.choices[self.pos]
1168 mem = ch in self.value
1173 val1 = self.genString(tmp[:ind])
1174 val2 = " "+self.genString(tmp[ind+1:])
1176 chstr = " "+description[ch]+" "
1178 chstr = "("+description[ch]+")"
1179 return ("mtext", val1+chstr+val2, range(len(val1),len(val1)+len(chstr)))
1181 def onDeselect(self, session):
1183 if not self.last_value == self.value:
1185 self.last_value = self.value[:]
1187 def tostring(self, value):
1190 def fromstring(self, val):
1193 class ConfigLocations(ConfigElement):
1194 def __init__(self, default = [], visible_width = False):
1195 ConfigElement.__init__(self)
1196 self.visible_width = visible_width
1198 self.default = default
1200 self.mountpoints = []
1201 harddiskmanager.on_partition_list_change.append(self.mountpointsChanged)
1202 self.value = default+[]
1204 def setValue(self, value):
1205 loc = [x[0] for x in self.locations if x[3]]
1206 add = [x for x in value if not x in loc]
1207 diff = add + [x for x in loc if not x in value]
1208 self.locations = [x for x in self.locations if not x[0] in diff] + [[x, self.getMountpoint(x), True, True] for x in add]
1209 self.locations.sort(key = lambda x: x[0])
1213 self.checkChangedMountpoints()
1214 for x in self.locations:
1216 return [x[0] for x in self.locations if x[3]]
1218 value = property(getValue, setValue)
1220 def tostring(self, value):
1223 def fromstring(self, val):
1227 sv = self.saved_value
1231 tmp = self.fromstring(sv)
1232 self.locations = [[x, None, False, False] for x in tmp]
1233 self.refreshMountpoints()
1234 for x in self.locations:
1235 if os.path.exists(x[0]):
1236 x[1] = self.getMountpoint(x[0])
1240 if self.save_disabled or self.locations == []:
1241 self.saved_value = None
1243 self.saved_value = self.tostring([x[0] for x in self.locations])
1245 def isChanged(self):
1246 sv = self.saved_value
1247 if val is None and self.locations == []:
1249 return self.tostring([x[0] for x in self.locations]) != sv
1251 def mountpointsChanged(self, action, dev):
1252 print "Mounts changed: ", action, dev
1253 mp = dev.mountpoint+"/"
1256 elif action == "remove":
1257 self.removedMount(mp)
1258 self.refreshMountpoints()
1260 def addedMount(self, mp):
1261 for x in self.locations:
1264 elif x[1] == None and os.path.exists(x[0]):
1265 x[1] = self.getMountpoint(x[0])
1268 def removedMount(self, mp):
1269 for x in self.locations:
1273 def refreshMountpoints(self):
1274 self.mountpoints = [p.mountpoint + "/" for p in harddiskmanager.getMountedPartitions() if p.mountpoint != "/"]
1275 self.mountpoints.sort(key = lambda x: -len(x))
1277 def checkChangedMountpoints(self):
1278 oldmounts = self.mountpoints
1279 self.refreshMountpoints()
1280 if oldmounts == self.mountpoints:
1283 if not x in self.mountpoints:
1284 self.removedMount(x)
1285 for x in self.mountpoints:
1286 if not x in oldmounts:
1289 def getMountpoint(self, file):
1290 file = os.path.realpath(file)+"/"
1291 for m in self.mountpoints:
1292 if file.startswith(m):
1296 def handleKey(self, key):
1300 self.pos = len(self.value)-1
1301 elif key == KEY_RIGHT:
1303 if self.pos >= len(self.value):
1305 elif key in [KEY_HOME, KEY_END]:
1309 return " ".join(self.value)
1311 def getMulti(self, selected):
1313 valstr = " ".join(self.value)
1314 if self.visible_width and len(valstr) > self.visible_width:
1315 return ("text", valstr[0:self.visible_width])
1317 return ("text", valstr)
1323 for val in self.value:
1326 valstr += str(val)+" "
1330 if self.visible_width and len(valstr) > self.visible_width:
1331 if ind1+1 < self.visible_width/2:
1334 off = min(ind1+1-self.visible_width/2, len(valstr)-self.visible_width)
1335 return ("mtext", valstr[off:off+self.visible_width], range(ind1-off,ind2-off))
1337 return ("mtext", valstr, range(ind1,ind2))
1339 def onDeselect(self, session):
1343 class ConfigNothing(ConfigSelection):
1345 ConfigSelection.__init__(self, choices = [""])
1347 # until here, 'saved_value' always had to be a *string*.
1348 # now, in ConfigSubsection, and only there, saved_value
1349 # is a dict, essentially forming a tree.
1351 # config.foo.bar=True
1352 # config.foobar=False
1355 # config.saved_value == {"foo": {"bar": "True"}, "foobar": "False"}
1359 class ConfigSubsectionContent(object):
1362 # we store a backup of the loaded configuration
1363 # data in self.stored_values, to be able to deploy
1364 # them when a new config element will be added,
1365 # so non-default values are instantly available
1367 # A list, for example:
1368 # config.dipswitches = ConfigSubList()
1369 # config.dipswitches.append(ConfigYesNo())
1370 # config.dipswitches.append(ConfigYesNo())
1371 # config.dipswitches.append(ConfigYesNo())
1372 class ConfigSubList(list, object):
1374 object.__init__(self)
1376 self.stored_values = {}
1386 def getSavedValue(self):
1388 for i in range(len(self)):
1389 sv = self[i].saved_value
1394 def setSavedValue(self, values):
1395 self.stored_values = dict(values)
1396 for (key, val) in self.stored_values.items():
1397 if int(key) < len(self):
1398 self[int(key)].saved_value = val
1400 saved_value = property(getSavedValue, setSavedValue)
1402 def append(self, item):
1404 list.append(self, item)
1405 if i in self.stored_values:
1406 item.saved_value = self.stored_values[i]
1411 for index in range(len(self)):
1412 res[str(index)] = self[index]
1415 # same as ConfigSubList, just as a dictionary.
1416 # care must be taken that the 'key' has a proper
1417 # str() method, because it will be used in the config
1419 class ConfigSubDict(dict, object):
1421 object.__init__(self)
1423 self.stored_values = {}
1426 for x in self.values():
1430 for x in self.values():
1433 def getSavedValue(self):
1435 for (key, val) in self.items():
1436 sv = val.saved_value
1441 def setSavedValue(self, values):
1442 self.stored_values = dict(values)
1443 for (key, val) in self.items():
1444 if str(key) in self.stored_values:
1445 val = self.stored_values[str(key)]
1447 saved_value = property(getSavedValue, setSavedValue)
1449 def __setitem__(self, key, item):
1450 dict.__setitem__(self, key, item)
1451 if str(key) in self.stored_values:
1452 item.saved_value = self.stored_values[str(key)]
1458 # Like the classes above, just with a more "native"
1461 # some evil stuff must be done to allow instant
1462 # loading of added elements. this is why this class
1465 # we need the 'content' because we overwrite
1467 # If you don't understand this, try adding
1468 # __setattr__ to a usual exisiting class and you will.
1469 class ConfigSubsection(object):
1471 object.__init__(self)
1472 self.__dict__["content"] = ConfigSubsectionContent()
1473 self.content.items = { }
1474 self.content.stored_values = { }
1476 def __setattr__(self, name, value):
1477 if name == "saved_value":
1478 return self.setSavedValue(value)
1479 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"
1480 self.content.items[name] = value
1481 if name in self.content.stored_values:
1482 #print "ok, now we have a new item,", name, "and have the following value for it:", self.content.stored_values[name]
1483 value.saved_value = self.content.stored_values[name]
1486 def __getattr__(self, name):
1487 return self.content.items[name]
1489 def getSavedValue(self):
1490 res = self.content.stored_values
1491 for (key, val) in self.content.items.items():
1492 sv = val.saved_value
1499 def setSavedValue(self, values):
1500 values = dict(values)
1502 self.content.stored_values = values
1504 for (key, val) in self.content.items.items():
1506 val.saved_value = values[key]
1508 saved_value = property(getSavedValue, setSavedValue)
1511 for x in self.content.items.values():
1515 for x in self.content.items.values():
1519 return self.content.items
1521 # the root config object, which also can "pickle" (=serialize)
1522 # down the whole config tree.
1524 # we try to keep non-existing config entries, to apply them whenever
1525 # a new config entry is added to a subsection
1526 # also, non-existing config entries will be saved, so they won't be
1527 # lost when a config entry disappears.
1528 class Config(ConfigSubsection):
1530 ConfigSubsection.__init__(self)
1532 def pickle_this(self, prefix, topickle, result):
1533 for (key, val) in topickle.items():
1534 name = prefix + "." + key
1536 if isinstance(val, dict):
1537 self.pickle_this(name, val, result)
1538 elif isinstance(val, tuple):
1539 result.append(name + "=" + val[0]) # + " ; " + val[1])
1541 result.append(name + "=" + val)
1545 self.pickle_this("config", self.saved_value, result)
1546 return '\n'.join(result) + "\n"
1548 def unpickle(self, lines):
1551 if not len(l) or l[0] == '#':
1555 val = l[n+1:].strip()
1557 names = l[:n].split('.')
1558 # if val.find(' ') != -1:
1559 # val = val[:val.find(' ')]
1563 for n in names[:-1]:
1564 base = base.setdefault(n, {})
1566 base[names[-1]] = val
1568 # we inherit from ConfigSubsection, so ...
1569 #object.__setattr__(self, "saved_value", tree["config"])
1570 if "config" in tree:
1571 self.setSavedValue(tree["config"])
1573 def saveToFile(self, filename):
1574 f = open(filename, "w")
1575 f.write(self.pickle())
1578 def loadFromFile(self, filename):
1579 f = open(filename, "r")
1580 self.unpickle(f.readlines())
1584 config.misc = ConfigSubsection()
1587 CONFIG_FILE = resolveFilename(SCOPE_CONFIG, "settings")
1591 config.loadFromFile(self.CONFIG_FILE)
1593 print "unable to load config (%s), assuming defaults..." % str(e)
1597 config.saveToFile(self.CONFIG_FILE)
1599 def __resolveValue(self, pickles, cmap):
1600 if cmap.has_key(pickles[0]):
1601 if len(pickles) > 1:
1602 return self.__resolveValue(pickles[1:], cmap[pickles[0]].dict())
1604 return str(cmap[pickles[0]].value)
1607 def getResolvedKey(self, key):
1608 names = key.split('.')
1610 if names[0] == "config":
1611 ret=self.__resolveValue(names[1:], config.content.items)
1612 if ret and len(ret):
1614 print "getResolvedKey", key, "failed !! (Typo??)"
1617 def NoSave(element):
1618 element.disableSave()
1621 configfile = ConfigFile()
1625 def getConfigListEntry(*args):
1626 assert len(args) > 1, "getConfigListEntry needs a minimum of two arguments (descr, configElement)"
1629 def updateConfigElement(element, newelement):
1630 newelement.value = element.value
1636 #config.bla = ConfigSubsection()
1637 #config.bla.test = ConfigYesNo()
1638 #config.nim = ConfigSubList()
1639 #config.nim.append(ConfigSubsection())
1640 #config.nim[0].bla = ConfigYesNo()
1641 #config.nim.append(ConfigSubsection())
1642 #config.nim[1].bla = ConfigYesNo()
1643 #config.nim[1].blub = ConfigYesNo()
1644 #config.arg = ConfigSubDict()
1645 #config.arg["Hello"] = ConfigYesNo()
1647 #config.arg["Hello"].handleKey(KEY_RIGHT)
1648 #config.arg["Hello"].handleKey(KEY_RIGHT)
1650 ##config.saved_value
1654 #print config.pickle()