configSelection is now saved to config file in a human readable style
[vuplus_dvbapp] / lib / python / Components / config.py
1 from time import *
2 from Tools.NumericalTextInput import *
3 from Tools.Directories import *
4
5 class configFile:
6         def __init__(self):
7                 self.changed = 0
8                 self.configElements = { }
9                 try:
10                         self.file = open(resolveFilename(SCOPE_CONFIG, "config"))
11                 except IOError:
12                         print "cannot open config file"
13                         return 
14                 
15                 while 1:
16                         line = self.file.readline()
17                         if line == "":
18                                 break
19                         
20                         if line.startswith("#"):                #skip comments
21                                 continue        
22                                 
23                         self.addElement(line)
24                 self.file.close()
25
26         def addElement(self, line):
27                 x = line.find("=")
28                 if x > -1:
29                         self.configElements[line[:x]] = line[x + 1:-1]
30         
31         def getKey(self, key):
32                 return self.configElements[key]
33
34         def setKey(self, key, value):
35                 self.changed = 1
36                 self.configElements[key] = value
37
38         def save(self):
39                 if self.changed == 0:           #no changes, so no write to disk needed
40                         return
41                         
42                 fileHandle = open(resolveFilename(SCOPE_CONFIG, "config"), "w")
43                 
44                 keys = self.configElements.keys()
45                 keys.sort()
46                 for x in keys:
47                         wstr = x + "=" + self.configElements[x] + "\n"
48
49                         fileHandle.write(wstr)
50
51                 fileHandle.close()              
52
53 class configSelection:
54         def __init__(self, parent):
55                 self.parent = parent
56                 
57         def checkValues(self):
58                 if self.parent.value < 0:
59                         self.parent.value = len(self.parent.vals) - 1   
60                 elif(self.parent.value > (len(self.parent.vals) - 1)):
61                         self.parent.value = 0
62
63         def cancel(self):
64                 self.parent.reload()
65
66         def save(self):
67                 self.parent.save()
68
69         def handleKey(self, key):
70                 if key == config.key["prevElement"]:
71                         self.parent.value = self.parent.value - 1
72                 if key == config.key["nextElement"]:
73                         self.parent.value = self.parent.value + 1
74                 
75                 self.checkValues()                      
76
77                 self.parent.change()
78
79         def __call__(self, selected):                   #needed by configlist
80                 self.checkValues()
81                 if isinstance(self.parent.vals[self.parent.value], str):
82                         returnValue = _(self.parent.vals[self.parent.value])
83                 else:
84                         returnValue = _(self.parent.vals[self.parent.value][1])
85
86                         
87                 print self.parent.vals[self.parent.value]
88                 
89                 return ("text", returnValue)
90                 
91 class configDateTime:
92         def __init__(self, parent):
93                 self.parent = parent
94                 
95         def checkValues(self):
96                 pass
97 #               if self.parent.value < 0:
98                         #self.parent.value = 0  
99
100                 #if(self.parent.value >= (len(self.parent.vals) - 1)):
101                         #self.parent.value = len(self.parent.vals) - 1
102
103         def cancel(self):
104                 self.parent.reload()
105
106         def save(self):
107                 self.parent.save()
108
109         def handleKey(self, key):
110                 if key == config.key["prevElement"]:
111                         self.parent.value = self.parent.value - self.parent.vals[1]
112                 if key == config.key["nextElement"]:
113                         self.parent.value = self.parent.value + self.parent.vals[1]
114                 
115                 self.checkValues()
116
117                 self.parent.change()    
118
119         def __call__(self, selected):                   #needed by configlist
120                 self.checkValues()
121                 return ("text", strftime(self.parent.vals[0], localtime(self.parent.value)))
122         
123 class configSatlist:
124         def __init__(self, parent):
125                 self.parent = parent
126
127         def checkValues(self):
128                 if self.parent.value < 0:
129                         self.parent.value = 0   
130
131                 if(self.parent.value >= (len(self.parent.vals) - 1)):
132                         self.parent.value = len(self.parent.vals) - 1
133                         
134         def cancel(self):
135                 self.parent.reload()
136
137         def save(self):
138                 self.parent.save()
139
140         def handleKey(self, key):
141                 if key == config.key["prevElement"]:
142                         self.parent.value = self.parent.value - 1
143                 if key == config.key["nextElement"]:
144                         self.parent.value = self.parent.value + 1
145                 
146                 self.checkValues()                      
147
148                 self.parent.change()    
149
150         def __call__(self, selected):                   #needed by configlist
151                 self.checkValues()
152                 #fixme
153                 return ("text", str(self.parent.vals[self.parent.value][0]))
154
155 class configSequenceArg:
156         def get(self, type, args = ()):
157                 # configsequencearg.get ("IP")
158                 if (type == "IP"):
159                         return (("."), [(0,255),(0,255),(0,255),(0,255)], "")
160                 # configsequencearg.get ("MAC")
161                 if (type == "MAC"):
162                         return ((":"), [(1,255),(1,255),(1,255),(1,255),(1,255),(1,255)], "")
163                 # configsequencearg.get ("CLOCK")
164                 if (type == "CLOCK"):
165                         return ((":"), [(0,23),(0,59)], "")
166                 # configsequencearg.get("INTEGER", (min, max)) => x with min <= x <= max
167                 if (type == "INTEGER"):
168                         return ((":"), [args], "")
169                 # configsequencearg.get("PINCODE", (number, "*")) => pin with number = length of pincode and "*" as numbers shown as stars
170                 # configsequencearg.get("PINCODE", (number, "")) => pin with number = length of pincode and numbers shown
171                 if (type == "PINCODE"):
172                         return ((":"), [(0, (10**args[0])-1)], args[1])
173                 # configsequencearg.get("FLOAT", [(min,max),(min1,max1)]) => x.y with min <= x <= max and min1 <= y <= max1
174                 if (type == "FLOAT"):
175                         return (("."), args, "")
176
177 configsequencearg = configSequenceArg()
178                 
179 class configSequence:
180         def __init__(self, parent):
181                 self.parent = parent
182                 self.markedPos = 0
183                 self.seperator = self.parent.vals[0]
184                 self.valueBounds = self.parent.vals[1]
185                 self.censorChar = self.parent.vals[2]
186
187         def checkValues(self):
188                 maxPos = 0
189                 num = 0
190                 for i in self.parent.value:
191                         maxPos += len(str(self.valueBounds[num][1]))
192                         while (self.valueBounds[num][0] > self.parent.value[num]):
193                                 self.parent.value[num] += 1
194
195                         while (self.valueBounds[num][1] < self.parent.value[num]):
196                                 self.parent.value[num] -= 1
197                                 
198 #                       if (self.valueBounds[num][0] <= i <= self.valueBounds[num][1]):
199                                 #pass
200                         #else:
201                                 #self.parent.value[num] = self.valueBounds[num][0]
202                         num += 1
203                 
204                 if self.markedPos >= maxPos:
205                         self.markedPos = maxPos - 1
206                 if self.markedPos < 0:
207                         self.markedPos = 0
208                         
209         def cancel(self):
210                 self.parent.reload()
211
212         def save(self):
213                 self.parent.save()
214
215         def handleKey(self, key):
216                 #this will no change anything on the value itself
217                 #so we can handle it here in gui element
218                 if key == config.key["prevElement"]:
219                         self.markedPos -= 1
220                 if key == config.key["nextElement"]:
221                         self.markedPos += 1
222                 
223                 if key >= config.key["0"] and key <= config.key["9"]:
224                         self.blockLen = []
225                         for x in self.valueBounds:
226                                 self.blockLen.append(len(str(x[1])))
227                                 
228                         pos = 0
229                         blocknumber = 0
230                         self.blockLenTotal = [0,]
231                         for x in self.blockLen:
232                                 pos += self.blockLen[blocknumber]
233                                 self.blockLenTotal.append(pos)
234                                 if (pos - 1 >= self.markedPos):
235                                         pass
236                                 else:
237                                         blocknumber += 1
238                                         
239                         number = 9 - config.key["9"] + key
240                         # length of numberblock
241                         numberLen = len(str(self.valueBounds[blocknumber][1]))
242                         # position in the block
243                         posinblock = self.markedPos - self.blockLenTotal[blocknumber]
244                         
245                         oldvalue = self.parent.value[blocknumber]
246                         olddec = oldvalue % 10 ** (numberLen - posinblock) - (oldvalue % 10 ** (numberLen - posinblock - 1))
247                         newvalue = oldvalue - olddec + (10 ** (numberLen - posinblock - 1) * number)
248                         
249                         print "You actually pressed a number (" + str(number) + ") which will be added at block number " + str(blocknumber) + " on position " + str(posinblock)
250                         print "Old value: " + str(oldvalue) + " olddec: " + str(olddec) + " newvalue: " + str(newvalue)
251                         self.parent.value[blocknumber] = newvalue
252                         self.markedPos += 1
253                 
254                 self.checkValues()                      
255                 
256                 print "markPos:",
257                 print self.markedPos
258
259                 #FIXME: dont call when press left/right
260                 self.parent.change()    
261
262         def __call__(self, selected):                   #needed by configlist
263                 value = ""
264                 mPos = self.markedPos
265                 print "Positon: " + str(mPos)
266                 num = 0;
267                 for i in self.parent.value:
268                         if len(value):  #fixme no heading separator possible
269                                 value += self.seperator
270                                 if mPos >= len(value) - 1:
271                                         mPos += 1
272                                 
273                         #diff =         self.valueBounds - len(str(i))
274                         #if diff > 0:
275                                 ## if this helps?!
276                                 #value += " " * diff
277                         print (("%0" + str(len(str(self.valueBounds[num][1]))) + "d") % i)
278                         if (self.censorChar == ""):
279                                 value += ("%0" + str(len(str(self.valueBounds[num][1]))) + "d") % i
280                         else:
281                                 value += (self.censorChar * len(str(self.valueBounds[num][1])))
282                         num += 1
283                         # only mark cursor when we are selected
284                         # (this code is heavily ink optimized!)
285                 if (self.parent.enabled == True):
286                         return ("mtext"[1-selected:], value, [mPos])
287                 else:
288                         return ("text", value)
289                 
290 class configText:
291         # used as first parameter
292         # is the text of a fixed size or is the user able to extend the length of the text
293         extendableSize = 1
294         fixedSize = 2
295
296         def __init__(self, parent):
297                 self.parent = parent
298                 self.markedPos = 0
299                 self.mode = self.parent.vals[0]
300                 self.textInput = NumericalTextInput(self.nextEntry)
301
302         def checkValues(self):
303                 if (self.markedPos < 0):
304                         self.markedPos = 0
305                 if (self.markedPos >= len(self.parent.value)):
306                         self.markedPos = len(self.parent.value) - 1
307                         
308         def cancel(self):
309                 self.parent.reload()
310
311         def save(self):
312                 self.parent.save()
313                 
314         def nextEntry(self):
315                 print self.parent
316                 self.parent.vals[1](self.parent.getConfigPath())
317
318         def handleKey(self, key):
319                 #this will no change anything on the value itself
320                 #so we can handle it here in gui element
321                 if key == config.key["delete"]:
322                         self.parent.value = self.parent.value[0:self.markedPos] + self.parent.value[self.markedPos + 1:]
323                 if key == config.key["prevElement"]:
324                         self.textInput.nextKey()
325                         self.markedPos -= 1
326
327                 if key == config.key["nextElement"]:
328                         self.textInput.nextKey()
329                         self.markedPos += 1
330                         if (self.mode == self.extendableSize):
331                                 if (self.markedPos >= len(self.parent.value)):
332                                         self.parent.value = self.parent.value.ljust(len(self.parent.value) + 1)
333                         
334                                 
335                 if key >= config.key["0"] and key <= config.key["9"]:
336                         number = 9 - config.key["9"] + key
337
338                         self.parent.value = self.parent.value[0:self.markedPos] + str(self.textInput.getKey(number)) + self.parent.value[self.markedPos + 1:]
339                 
340                 self.checkValues()                      
341                 
342                 self.parent.change()    
343
344         def __call__(self, selected):                   #needed by configlist
345                 return ("mtext"[1-selected:], str(self.parent.value), [self.markedPos])
346                 
347 class configValue:
348         def __init__(self, obj):
349                 self.obj = obj
350                 
351         def __str__(self):
352                 return self.obj
353
354 class Config:
355         def __init__(self):
356                 self.key = { "choseElement": 0,
357                                          "prevElement": 1,
358                                          "nextElement": 2,
359                                          "delete": 3,
360                                          "0": 10,
361                                          "1": 11,
362                                          "2": 12,
363                                          "3": 13,
364                                          "4": 14,
365                                          "5": 15,
366                                          "6": 16,
367                                          "7": 17,
368                                          "8": 18,
369                                          "9": 19 }
370                 
371 config = Config();
372
373 configfile = configFile()
374
375 class ConfigSlider:
376         def __init__(self, parent):
377                 self.parent = parent
378
379         def cancel(self):
380                 self.parent.reload()
381
382         def save(self):
383                 self.parent.save()
384
385         def checkValues(self):
386                 if self.parent.value < 0:
387                         self.parent.value = 0   
388
389                 if self.parent.value > 10:
390                         self.parent.value = 10  
391
392         def handleKey(self, key):
393                 if key == config.key["prevElement"]:
394                         self.parent.value = self.parent.value - 1
395                 if key == config.key["nextElement"]:
396                         self.parent.value = self.parent.value + 1
397                                         
398                 self.checkValues()      
399                 self.parent.change()    
400
401         def __call__(self, selected):                   #needed by configlist
402                 self.checkValues()
403                 return ("slider", self.parent.value * 10)
404
405 class ConfigSubsection:
406         def __init__(self):
407                 pass
408
409 class configElement:
410
411         def getIndexbyEntry(self, data):
412                 cnt = 0;
413                 tcnt = -1; #for defaultval
414                 for x in self.vals:
415                         if int(x[1]) == int(data):
416                                         return cnt
417                         if int(x[1]) == int(self.defaultValue):
418                                         tcnt = cnt
419                         cnt += 1
420                 if tcnt != -1:
421                         return tcnt
422                 return 0        #prevent bigger then array
423
424         def datafromFile(self, control, data):
425                 if control == ConfigSlider:
426                         return int(data)
427                 elif control == configSelection:
428                         try:
429                                 return int(data)
430                         except:
431                                 for x in data.split(":"):
432                                         if x[0] == "*":
433                                                 count = 0
434                                                 for y in self.vals:
435                                                         if y[0] == x[1:-1]:
436                                                                 return count
437                                                         count += 1
438                                 return self.defaultValue
439                 elif control == configDateTime:
440                         return int(data)
441                 elif control == configText:
442                         return str(data)
443                 elif control == configSequence:
444                         list = [ ]
445                         part = data.split(self.vals[0])
446                         for x in part:
447                                 list.append(int(x))
448                         return list
449                 elif control == configSatlist:
450                         return self.getIndexbyEntry(data)
451                 else: 
452                         return ""       
453
454         def datatoFile(self, control, data):
455                 if control == ConfigSlider:
456                         return str(data)
457                 elif control == configSelection:
458                         if isinstance(self.vals[data], str):
459                                 return str(data)
460                         else:
461                                 confList = []
462                                 count = 0
463                                 for x in self.vals:
464                                         if count == data:
465                                                 confList.append("*" + str(x[0] + "*"))
466                                         else:
467                                                 confList.append(x[0])
468                                         count += 1
469                                 return ":".join(confList)
470                         return str(data)
471                 elif control == configDateTime:
472                         return str(data)
473                 elif control == configText:
474                         return str(data.strip())
475
476                 elif control == configSequence:
477                         print data
478                         try:
479                                 value = ((len(data) * ("%d" + self.vals[0]))[0:-1]) % tuple(data)
480                         except: 
481                                 value = str(data)       
482 #                       just in case you don't understand the above, here an equivalent:
483 #                       value = ""
484 #                       for i in data:
485 #                               if value !="":
486 #                                       value += self.vals[0]
487 #                               value += str(i)
488                         return value
489                 elif control == configSatlist:
490                         return str(self.vals[self.value][1]);
491                 else: 
492                         return ""       
493
494         def loadData(self):
495                 #print "load:" + self.configPath
496                 try:
497                         value = self.datafromFile(self.controlType, configfile.getKey(self.configPath))
498                 except:         
499                         value = ""
500
501                 if value == "":
502                         #print "value not found - using default"
503
504                         if self.controlType == configSatlist:
505                                 self.value = self.getIndexbyEntry(self.defaultValue)
506                         else:   
507                                 self.value = self.defaultValue
508
509                         self.save()             #add missing value to dict
510                 else:
511                         #print "set val:" + str(value)
512                         self.value = value
513                         
514                 #is this right? activate settings after load/cancel and use default     
515                 self.change()
516
517         def __init__(self, configPath, control, defaultValue, vals):
518                 self.configPath = configPath
519                 self.defaultValue = defaultValue
520                 self.controlType = control
521                 self.vals = vals
522                 self.notifierList = [ ]
523                 self.enabled = True
524                 self.loadData()         
525                 
526         def getConfigPath(self):
527                 return self.configPath
528         
529         def addNotifier(self, notifier):
530                 self.notifierList.append(notifier);
531                 notifier(self);
532         def change(self):
533                 for notifier in self.notifierList:
534                         notifier(self)
535         def reload(self):
536                 self.loadData()
537         def save(self):
538                 configfile.setKey(self.configPath, self.datatoFile(self.controlType,self.value))
539
540 class configElement_nonSave(configElement):
541         def __init__(self, configPath, control, defaultValue, vals):
542                 configElement.__init__(self, configPath, control, defaultValue, vals)
543
544         def save(self):
545                 pass
546                 
547 def getConfigListEntry(description, element):
548         b = element
549         item = b.controlType(b)
550         return ((description, item))
551
552
553 def configElementBoolean(name, default, texts=(_("Enable"), _("Disable"))):
554         return configElement(name, configSelection, default, texts)
555
556 config.misc = ConfigSubsection()