code cleanup in ChannelSelection,
[enigma2.git] / lib / python / Screens / ChannelSelection.py
1 from Screen import Screen
2 from Components.Button import Button
3 from Components.ServiceList import ServiceList
4 from Components.ActionMap import NumberActionMap, ActionMap
5 from Components.MenuList import MenuList
6 from Components.ServiceEventTracker import ServiceEventTracker
7 from EpgSelection import EPGSelection
8 from enigma import eServiceReference, eEPGCache, eServiceCenter, eServiceCenterPtr, iMutableServiceListPtr, iStaticServiceInformationPtr, eTimer, eDVBDB, iPlayableService, iServiceInformation
9 from Components.config import config, ConfigSubsection, ConfigText
10 from Screens.FixedMenu import FixedMenu
11 from Tools.NumericalTextInput import NumericalTextInput
12 from Components.NimManager import nimmanager
13 from Components.Sources.Clock import Clock
14 from Components.Input import Input
15 from Components.ParentalControl import parentalControl
16 from Screens.InputBox import InputBox, PinInput
17 from Screens.MessageBox import MessageBox
18 from ServiceReference import ServiceReference
19 from Tools.BoundFunction import boundFunction
20 from re import *
21 from os import remove
22
23 FLAG_SERVICE_NEW_FOUND = 64 #define in lib/dvb/idvb.h as dxNewFound = 64
24
25 import xml.dom.minidom
26
27 class BouquetSelector(Screen):
28         def __init__(self, session, bouquets, selectedFunc, enableWrapAround=False):
29                 Screen.__init__(self, session)
30
31                 self.selectedFunc=selectedFunc
32
33                 self["actions"] = ActionMap(["OkCancelActions"],
34                         {
35                                 "ok": self.okbuttonClick,
36                                 "cancel": self.cancelClick
37                         })
38                 entrys = [ ]
39                 for x in bouquets:
40                         entrys.append((x[0], x[1]))
41                 self["menu"] = MenuList(entrys, enableWrapAround)
42
43         def getCurrent(self):
44                 cur = self["menu"].getCurrent()
45                 return cur and cur[1]
46
47         def okbuttonClick(self):
48                 self.selectedFunc(self.getCurrent())
49
50         def up(self):
51                 self["menu"].up()
52
53         def down(self):
54                 self["menu"].down()
55
56         def cancelClick(self):
57                 self.close(False)
58
59 class ChannelContextMenu(Screen):
60         def __init__(self, session, csel):
61                 Screen.__init__(self, session)
62                 self.csel = csel
63                 self.bsel = None
64
65                 self["actions"] = ActionMap(["OkCancelActions"],
66                         {
67                                 "ok": self.okbuttonClick,
68                                 "cancel": self.cancelClick
69                         })
70                 menu = [ ]
71
72                 current_root = csel.getRoot()
73                 current_sel_path = csel.getCurrentSelection().getPath()
74                 current_sel_flags = csel.getCurrentSelection().flags
75                 inBouquetRootList = current_root and current_root.getPath().find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
76                 inBouquet = csel.getMutableList() is not None
77                 haveBouquets = config.usage.multibouquet.value
78
79                 if not csel.bouquet_mark_edit and not csel.movemode:
80                         if not inBouquetRootList:
81                                 if (csel.getCurrentSelection().flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
82                                         if config.ParentalControl.configured.value:
83                                                 if parentalControl.getProtectionLevel(csel.getCurrentSelection().toCompareString()) == -1:
84                                                         menu.append((_("add to parental protection"), boundFunction(self.addParentalProtection, csel.getCurrentSelection())))
85                                                 else:
86                                                         menu.append((_("remove from parental protection"), boundFunction(self.removeParentalProtection, csel.getCurrentSelection())))
87                                         if haveBouquets:
88                                                 menu.append((_("add service to bouquet"), self.addServiceToBouquetSelected))
89                                         else:
90                                                 menu.append((_("add service to favourites"), self.addServiceToBouquetSelected))
91                                 else:
92                                         if haveBouquets:
93                                                 if not inBouquet and current_sel_path.find("PROVIDERS") == -1:
94                                                         menu.append((_("copy to bouquets"), self.copyCurrentToBouquetList))
95                                         if current_sel_path.find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
96                                                 menu.append((_("remove all new found flags"), self.removeAllNewFoundFlags))
97                                 if inBouquet:
98                                         menu.append((_("remove entry"), self.removeCurrentService))
99                                 if current_root is not None and current_root.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
100                                         menu.append((_("remove new found flag"), self.removeNewFoundFlag))
101                         else:
102                                         menu.append((_("add bouquet"), self.showBouquetInputBox))
103                                         menu.append((_("remove entry"), self.removeBouquet))
104
105                 if inBouquet: # current list is editable?
106                         if not csel.bouquet_mark_edit:
107                                 if not csel.movemode:
108                                         menu.append((_("add marker"), self.showMarkerInputBox))
109                                         menu.append((_("enable move mode"), self.toggleMoveMode))
110                                         if not inBouquetRootList:
111                                                 if haveBouquets:
112                                                         menu.append((_("enable bouquet edit"), self.bouquetMarkStart))
113                                                 else:
114                                                         menu.append((_("enable favourite edit"), self.bouquetMarkStart))
115                                 else:
116                                         menu.append((_("disable move mode"), self.toggleMoveMode))
117                         elif not inBouquetRootList:
118                                 if haveBouquets:
119                                         menu.append((_("end bouquet edit"), self.bouquetMarkEnd))
120                                         menu.append((_("abort bouquet edit"), self.bouquetMarkAbort))
121                                 else:
122                                         menu.append((_("end favourites edit"), self.bouquetMarkEnd))
123                                         menu.append((_("abort favourites edit"), self.bouquetMarkAbort))
124
125                 menu.append((_("back"), self.cancelClick))
126                 self["menu"] = MenuList(menu)
127
128         def okbuttonClick(self):
129                 self["menu"].getCurrent()[1]()
130
131         def cancelClick(self):
132                 self.close(False)
133                 
134         def showBouquetInputBox(self):
135                 self.session.openWithCallback(self.bouquetInputCallback, InputBox, title=_("Please enter a name for the new bouquet"), text="bouquetname", maxSize=False, type=Input.TEXT)
136
137         def bouquetInputCallback(self, bouquet):
138                 if bouquet is not None:
139                         self.csel.addBouquet(bouquet, None)
140                 self.close()
141
142         def addParentalProtection(self, service):
143                 parentalControl.protectService(service.toCompareString())
144                 self.close()
145
146         def removeParentalProtection(self, service):
147                 self.session.openWithCallback(boundFunction(self.pinEntered, service.toCompareString()), PinInput, pinList = [config.ParentalControl.servicepin[0].value], triesEntry = config.ParentalControl.retries.servicepin, title = _("Enter the service pin"), windowTitle = _("Change pin code"))
148
149         def pinEntered(self, service, result):
150                 if result:
151                         parentalControl.unProtectService(service)
152                         self.close()
153                 else:
154                         self.session.openWithCallback(self.close, MessageBox, _("The pin code you entered is wrong."), MessageBox.TYPE_ERROR)
155
156         def addServiceToBouquetSelected(self):
157                 bouquets = self.csel.getBouquetList()
158                 if bouquets is None:
159                         cnt = 0
160                 else:
161                         cnt = len(bouquets)
162                 if cnt > 1: # show bouquet list
163                         self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, bouquets, self.addCurrentServiceToBouquet)
164                 elif cnt == 1: # add to only one existing bouquet
165                         self.addCurrentServiceToBouquet(bouquets[0][1])
166
167         def bouquetSelClosed(self, recursive):
168                 self.bsel = None
169                 if recursive:
170                         self.close(False)
171
172         def copyCurrentToBouquetList(self):
173                 self.csel.copyCurrentToBouquetList()
174                 self.close()
175
176         def removeBouquet(self):
177                 self.csel.removeBouquet()
178                 self.close()
179
180         def showMarkerInputBox(self):
181                 self.session.openWithCallback(self.markerInputCallback, InputBox, title=_("Please enter a name for the new marker"), text="markername", maxSize=False, type=Input.TEXT)
182
183         def markerInputCallback(self, marker):
184                 if marker is not None:
185                         self.csel.addMarker(marker)
186                 self.close()
187
188         def addCurrentServiceToBouquet(self, dest):
189                 self.csel.addServiceToBouquet(dest)
190                 if self.bsel is not None:
191                         self.bsel.close(True)
192                 else:
193                         self.close(True) # close bouquet selection
194
195         def removeCurrentService(self):
196                 self.csel.removeCurrentService()
197                 self.close()
198
199         def toggleMoveMode(self):
200                 self.csel.toggleMoveMode()
201                 self.close()
202
203         def bouquetMarkStart(self):
204                 self.csel.startMarkedEdit()
205                 self.close()
206
207         def bouquetMarkEnd(self):
208                 self.csel.endMarkedEdit(abort=False)
209                 self.close()
210
211         def bouquetMarkAbort(self):
212                 self.csel.endMarkedEdit(abort=True)
213                 self.close()
214
215         def removeNewFoundFlag(self):
216                 eDVBDB.getInstance().removeFlag(self.csel.getCurrentSelection(), FLAG_SERVICE_NEW_FOUND)
217                 self.close()
218
219         def removeAllNewFoundFlags(self):
220                 curpath = self.csel.getCurrentSelection().getPath()
221                 idx = curpath.find("satellitePosition == ")
222                 if idx != -1:
223                         tmp = curpath[idx+21:]
224                         idx = tmp.find(')')
225                         if idx != -1:
226                                 satpos = int(tmp[:idx])
227                                 eDVBDB.getInstance().removeFlags(FLAG_SERVICE_NEW_FOUND, -1, -1, -1, satpos)
228                 self.close()
229
230 class ChannelSelectionEPG:
231         def __init__(self):
232                 self["ChannelSelectEPGActions"] = ActionMap(["ChannelSelectEPGActions"],
233                         {
234                                 "showEPGList": self.showEPGList,
235                         })
236
237         def showEPGList(self):
238                 ref=self.getCurrentSelection()
239                 ptr=eEPGCache.getInstance()
240                 if ptr.startTimeQuery(ref) != -1:
241                         self.session.open(EPGSelection, ref)
242                 else:
243                         print 'no epg for service', ref.toString()
244
245 class ChannelSelectionEdit:
246         def __init__(self):
247                 self.entry_marked = False
248                 self.movemode = False
249                 self.bouquet_mark_edit = False
250                 self.mutableList = None
251                 self.__marked = [ ]
252                 self.saved_title = None
253                 self.saved_root = None
254
255                 class ChannelSelectionEditActionMap(ActionMap):
256                         def __init__(self, csel, contexts = [ ], actions = { }, prio=0):
257                                 ActionMap.__init__(self, contexts, actions, prio)
258                                 self.csel = csel
259
260                         def action(self, contexts, action):
261                                 if action == "cancel":
262                                         self.csel.handleEditCancel()
263                                         return 0 # fall-trough
264                                 elif action == "ok":
265                                         return 0 # fall-trough
266                                 else:
267                                         return ActionMap.action(self, contexts, action)
268
269                 self["ChannelSelectEditActions"] = ChannelSelectionEditActionMap(self, ["ChannelSelectEditActions", "OkCancelActions"],
270                         {
271                                 "contextMenu": self.doContext,
272                         })
273
274         def getMutableList(self, root=eServiceReference()):
275                 if not self.mutableList is None:
276                         return self.mutableList
277                 serviceHandler = eServiceCenter.getInstance()
278                 if not root.valid():
279                         root=self.getRoot()
280                 list = root and serviceHandler.list(root)
281                 if list is not None:
282                         return list.startEdit()
283                 return None
284
285         def buildBouquetID(self, str):
286                 tmp = str.lower()
287                 name = ''
288                 for c in tmp:
289                         if (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9'):
290                                 name += c
291                         else:
292                                 name += '_'
293                 return name
294
295         def addMarker(self, name):
296                 current = self.servicelist.getCurrent()
297                 mutableList = self.getMutableList()
298                 cnt = 0
299                 while mutableList:
300                         str = '1:64:%d:0:0:0:0:0:0:0::%s'%(cnt, name)
301                         ref = eServiceReference(str)
302                         if current and current.valid():
303                                 if not mutableList.addService(ref, current):
304                                         self.servicelist.addService(ref, True)
305                                         mutableList.flushChanges()
306                                         break
307                         elif not mutableList.addService(ref):
308                                 self.servicelist.addService(ref, True)
309                                 mutableList.flushChanges()
310                                 break
311                         cnt+=1
312
313         def addBouquet(self, bName, services):
314                 serviceHandler = eServiceCenter.getInstance()
315                 mutableBouquetList = serviceHandler.list(self.bouquet_root).startEdit()
316                 if mutableBouquetList:
317                         if self.mode == MODE_TV:
318                                 bName += " (TV)"
319                                 str = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET \"userbouquet.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(bName))
320                         else:
321                                 bName += " (Radio)"
322                                 str = '1:7:2:0:0:0:0:0:0:0:(type == 2) FROM BOUQUET \"userbouquet.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(bName))
323                         new_bouquet_ref = eServiceReference(str)
324                         if not mutableBouquetList.addService(new_bouquet_ref):
325                                 mutableBouquetList.flushChanges()
326                                 eDVBDB.getInstance().reloadBouquets()
327                                 mutableBouquet = serviceHandler.list(new_bouquet_ref).startEdit()
328                                 if mutableBouquet:
329                                         mutableBouquet.setListName(bName)
330                                         if services is not None:
331                                                 for service in services:
332                                                         if mutableBouquet.addService(service):
333                                                                 print "add", service.toString(), "to new bouquet failed"
334                                         mutableBouquet.flushChanges()
335                                 else:
336                                         print "get mutable list for new created bouquet failed"
337                                 # do some voodoo to check if current_root is equal to bouquet_root
338                                 cur_root = self.getRoot();
339                                 str1 = cur_root.toString()
340                                 pos1 = str1.find("FROM BOUQUET")
341                                 pos2 = self.bouquet_rootstr.find("FROM BOUQUET")
342                                 if pos1 != -1 and pos2 != -1 and str1[pos1:] == self.bouquet_rootstr[pos2:]:
343                                         self.servicelist.addService(new_bouquet_ref)
344                         else:
345                                 print "add", str, "to bouquets failed"
346                 else:
347                         print "bouquetlist is not editable"
348
349         def copyCurrentToBouquetList(self):
350                 provider = ServiceReference(self.getCurrentSelection())
351                 providerName = provider.getServiceName()
352                 serviceHandler = eServiceCenter.getInstance()
353                 services = serviceHandler.list(provider.ref)
354                 self.addBouquet(providerName, services and services.getContent('R', True))
355
356         def removeBouquet(self):
357                 refstr = self.getCurrentSelection().toString()
358                 self.bouquetNumOffsetCache = { }
359                 pos = refstr.find('FROM BOUQUET "')
360                 filename = None
361                 if pos != -1:
362                         refstr = refstr[pos+14:]
363                         pos = refstr.find('"')
364                         if pos != -1:
365                                 filename = '/etc/enigma2/' + refstr[:pos] # FIXMEEE !!! HARDCODED /etc/enigma2
366                 self.removeCurrentService()
367                 try:
368                         if filename is not None:
369                                 remove(filename)
370                 except OSError:
371                         print "error during remove of", filename
372
373 #  multiple marked entry stuff ( edit mode, later multiepg selection )
374         def startMarkedEdit(self):
375                 self.mutableList = self.getMutableList()
376                 # add all services from the current list to internal marked set in listboxservicecontent
377                 self.clearMarks() # this clears the internal marked set in the listboxservicecontent
378                 self.saved_title = self.instance.getTitle()
379                 pos = self.saved_title.find(')')
380                 new_title = self.saved_title[:pos+1]
381                 if config.usage.multibouquet.value:
382                         new_title += ' ' + _("[bouquet edit]")
383                 else:
384                         new_title += ' ' + _("[favourite edit]")
385                 self.setTitle(new_title)
386                 self.bouquet_mark_edit = True
387                 self.__marked = self.servicelist.getRootServices()
388                 for x in self.__marked:
389                         self.servicelist.addMarked(eServiceReference(x))
390                 self.savedPath = self.servicePath[:]
391                 self.showAllServices()
392
393         def endMarkedEdit(self, abort):
394                 if not abort and self.mutableList is not None:
395                         self.bouquetNumOffsetCache = { }
396                         new_marked = set(self.servicelist.getMarked())
397                         old_marked = set(self.__marked)
398                         removed = old_marked - new_marked
399                         added = new_marked - old_marked
400                         changed = False
401                         for x in removed:
402                                 changed = True
403                                 self.mutableList.removeService(eServiceReference(x))
404                         for x in added:
405                                 changed = True
406                                 self.mutableList.addService(eServiceReference(x))
407                         if changed:
408                                 self.mutableList.flushChanges()
409                 self.__marked = []
410                 self.clearMarks()
411                 self.bouquet_mark_edit = False
412                 self.mutableList = None
413                 self.setTitle(self.saved_title)
414                 self.saved_title = None
415                 # self.servicePath is just a reference to servicePathTv or Radio...
416                 # so we never ever do use the asignment operator in self.servicePath
417                 del self.servicePath[:] # remove all elements
418                 self.servicePath += self.savedPath # add saved elements
419                 del self.savedPath
420                 self.setRoot(self.servicePath[len(self.servicePath)-1])
421
422         def clearMarks(self):
423                 self.servicelist.clearMarks()
424
425         def doMark(self):
426                 ref = self.servicelist.getCurrent()
427                 if self.servicelist.isMarked(ref):
428                         self.servicelist.removeMarked(ref)
429                 else:
430                         self.servicelist.addMarked(ref)
431
432         def removeCurrentService(self):
433                 ref = self.servicelist.getCurrent()
434                 mutableList = self.getMutableList()
435                 if ref.valid() and mutableList is not None:
436                         if not mutableList.removeService(ref):
437                                 self.bouquetNumOffsetCache = { }
438                                 mutableList.flushChanges() #FIXME dont flush on each single removed service
439                                 self.servicelist.removeCurrent()
440
441         def addServiceToBouquet(self, dest, service=None):
442                 mutableList = self.getMutableList(dest)
443                 if not mutableList is None:
444                         if service is None: #use current selected service
445                                 service = self.servicelist.getCurrent()
446                         if not mutableList.addService(service):
447                                 self.bouquetNumOffsetCache = { }
448                                 mutableList.flushChanges()
449                                 # do some voodoo to check if current_root is equal to dest
450                                 cur_root = self.getRoot();
451                                 str1 = cur_root.toString()
452                                 str2 = dest.toString()
453                                 pos1 = str1.find("FROM BOUQUET")
454                                 pos2 = str2.find("FROM BOUQUET")
455                                 if pos1 != -1 and pos2 != -1 and str1[pos1:] == str2[pos2:]:
456                                         self.servicelist.addService(service)
457
458         def toggleMoveMode(self):
459                 if self.movemode:
460                         if self.entry_marked:
461                                 self.toggleMoveMarked() # unmark current entry
462                         self.movemode = False
463                         self.pathChangeDisabled = False # re-enable path change
464                         self.mutableList.flushChanges() # FIXME add check if changes was made
465                         self.mutableList = None
466                         self.setTitle(self.saved_title)
467                         self.saved_title = None
468                         if self.getRoot() == self.bouquet_root:
469                                 self.bouquetNumOffsetCache = { }
470                 else:
471                         self.mutableList = self.getMutableList()
472                         self.movemode = True
473                         self.pathChangeDisabled = True # no path change allowed in movemode
474                         self.saved_title = self.instance.getTitle()
475                         new_title = self.saved_title
476                         pos = self.saved_title.find(')')
477                         new_title = self.saved_title[:pos+1] + ' ' + _("[move mode]") + self.saved_title[pos+1:]
478                         self.setTitle(new_title);
479
480         def handleEditCancel(self):
481                 if self.movemode: #movemode active?
482                         self.channelSelected() # unmark
483                         self.toggleMoveMode() # disable move mode
484                 elif self.bouquet_mark_edit:
485                         self.endMarkedEdit(True) # abort edit mode
486
487         def toggleMoveMarked(self):
488                 if self.entry_marked:
489                         self.servicelist.setCurrentMarked(False)
490                         self.entry_marked = False
491                 else:
492                         self.servicelist.setCurrentMarked(True)
493                         self.entry_marked = True
494
495         def doContext(self):
496                 self.session.open(ChannelContextMenu, self)
497
498 MODE_TV = 0
499 MODE_RADIO = 1
500
501 # this makes it much simple to implement a selectable radio or tv mode :)
502 service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 195) || (type == 25)'
503 service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2)'
504
505 class ChannelSelectionBase(Screen):
506         def __init__(self, session):
507                 Screen.__init__(self, session)
508
509                 self["key_red"] = Button(_("All"))
510                 self["key_green"] = Button(_("Satellites"))
511                 self["key_yellow"] = Button(_("Provider"))
512                 self["key_blue"] = Button(_("Favourites"))
513
514                 self["list"] = ServiceList()
515                 self.servicelist = self["list"]
516
517                 self.numericalTextInput = NumericalTextInput()
518                 self.numericalTextInput.setUseableChars(u'1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ')
519
520                 self.servicePathTV = [ ]
521                 self.servicePathRadio = [ ]
522                 self.servicePath = [ ]
523
524                 self.mode = MODE_TV
525
526                 self.pathChangeDisabled = False
527
528                 self.bouquetNumOffsetCache = { }
529
530                 self["ChannelSelectBaseActions"] = NumberActionMap(["ChannelSelectBaseActions", "NumberActions"],
531                         {
532                                 "showFavourites": self.showFavourites,
533                                 "showAllServices": self.showAllServices,
534                                 "showProviders": self.showProviders,
535                                 "showSatellites": self.showSatellites,
536                                 "nextBouquet": self.nextBouquet,
537                                 "prevBouquet": self.prevBouquet,
538                                 "nextMarker": self.nextMarker,
539                                 "prevMarker": self.prevMarker,
540                                 "1": self.keyNumberGlobal,
541                                 "2": self.keyNumberGlobal,
542                                 "3": self.keyNumberGlobal,
543                                 "4": self.keyNumberGlobal,
544                                 "5": self.keyNumberGlobal,
545                                 "6": self.keyNumberGlobal,
546                                 "7": self.keyNumberGlobal,
547                                 "8": self.keyNumberGlobal,
548                                 "9": self.keyNumberGlobal,
549                                 "0": self.keyNumber0
550                         })
551                 self.recallBouquetMode()
552
553         def appendDVBTypes(self, ref):
554                 path = ref.getPath()
555                 pos = path.find(' FROM BOUQUET')
556                 if pos != -1:
557                         return eServiceReference(self.service_types + path[pos:])
558                 return ref
559
560         def getBouquetNumOffset(self, bouquet):
561                 if not config.usage.multibouquet.value:
562                         return 0
563                 bouquet = self.appendDVBTypes(bouquet)
564                 str = bouquet.toString()
565                 offsetCount = 0
566                 if not self.bouquetNumOffsetCache.has_key(str):
567                         serviceHandler = eServiceCenter.getInstance()
568                         bouquetlist = serviceHandler.list(self.bouquet_root)
569                         if not bouquetlist is None:
570                                 while True:
571                                         bouquetIterator = self.appendDVBTypes(bouquetlist.getNext())
572                                         if not bouquetIterator.valid(): #end of list
573                                                 break
574                                         self.bouquetNumOffsetCache[bouquetIterator.toString()]=offsetCount
575                                         if ((bouquetIterator.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory):
576                                                 continue
577                                         servicelist = serviceHandler.list(bouquetIterator)
578                                         if not servicelist is None:
579                                                 while True:
580                                                         serviceIterator = servicelist.getNext()
581                                                         if not serviceIterator.valid(): #check if end of list
582                                                                 break
583                                                         if serviceIterator.flags: #playable services have no flags
584                                                                 continue
585                                                         offsetCount += 1
586                 return self.bouquetNumOffsetCache.get(str, offsetCount)
587
588         def recallBouquetMode(self):
589                 if self.mode == MODE_TV:
590                         self.service_types = service_types_tv
591                         if config.usage.multibouquet.value:
592                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.tv" ORDER BY bouquet'
593                         else:
594                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)
595                 else:
596                         self.service_types = service_types_radio
597                         if config.usage.multibouquet.value:
598                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.radio" ORDER BY bouquet'
599                         else:
600                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(self.service_types)
601                 self.bouquet_root = eServiceReference(self.bouquet_rootstr)
602
603         def setTvMode(self):
604                 self.mode = MODE_TV
605                 self.servicePath = self.servicePathTV
606                 self.recallBouquetMode()
607                 title = self.instance.getTitle()
608                 pos = title.find(" (")
609                 if pos != -1:
610                         title = title[:pos]
611                 title += " (TV)"
612                 self.setTitle(title)
613
614         def setRadioMode(self):
615                 self.mode = MODE_RADIO
616                 self.servicePath = self.servicePathRadio
617                 self.recallBouquetMode()
618                 title = self.instance.getTitle()
619                 pos = title.find(" (")
620                 if pos != -1:
621                         title = title[:pos]
622                 title += " (Radio)"
623                 self.setTitle(title)
624
625         def setRoot(self, root, justSet=False):
626                 path = root.getPath()
627                 inBouquetRootList = path.find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
628                 pos = path.find(' FROM BOUQUET')
629                 isBouquet = pos != -1
630                 if not inBouquetRootList and isBouquet:
631                         self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
632                         self.servicelist.setNumberOffset(self.getBouquetNumOffset(root))
633                         refstr = self.service_types + path[pos:]
634                         root = eServiceReference(refstr)
635                 else:
636                         self.servicelist.setMode(ServiceList.MODE_NORMAL)
637                 self.servicelist.setRoot(root, justSet)
638                 self.buildTitleString()
639
640         def removeModeStr(self, str):
641                 if self.mode == MODE_TV:
642                         pos = str.find(' (TV)')
643                 else:
644                         pos = str.find(' (Radio)')
645                 if pos != -1:
646                         return str[:pos]
647                 return str
648
649         def getServiceName(self, ref):
650                 str = self.removeModeStr(ServiceReference(ref).getServiceName())
651                 if not len(str):
652                         pathstr = ref.getPath()
653                         if pathstr.find('FROM PROVIDERS') != -1:
654                                 return _("Provider")
655                         if pathstr.find('FROM SATELLITES') != -1:
656                                 return _("Satellites")
657                         if pathstr.find(') ORDER BY name') != -1:
658                                 return _("All")
659                 return str
660
661         def buildTitleString(self):
662                 titleStr = self.instance.getTitle()
663                 pos = titleStr.find(']')
664                 if pos == -1:
665                         pos = titleStr.find(')')
666                 if pos != -1:
667                         titleStr = titleStr[:pos+1]
668                         Len = len(self.servicePath)
669                         if Len > 0:
670                                 base_ref = self.servicePath[0]
671                                 if Len > 1:
672                                         end_ref = self.servicePath[Len-1]
673                                 else:
674                                         end_ref = None
675                                 nameStr = self.getServiceName(base_ref)
676                                 titleStr += ' ' + nameStr
677                                 if end_ref is not None:
678                                         if Len > 2:
679                                                 titleStr += '/../'
680                                         else:
681                                                 titleStr += '/'
682                                         nameStr = self.getServiceName(end_ref)
683                                         titleStr += nameStr
684                                 self.setTitle(titleStr)
685
686         def moveUp(self):
687                 self.servicelist.moveUp()
688
689         def moveDown(self):
690                 self.servicelist.moveDown()
691
692         def clearPath(self):
693                 del self.servicePath[:]
694
695         def enterPath(self, ref, justSet=False):
696                 self.servicePath.append(ref)
697                 self.setRoot(ref, justSet)
698
699         def pathUp(self, justSet=False):
700                 prev = self.servicePath.pop()
701                 length = len(self.servicePath)
702                 if length:
703                         current = self.servicePath[length-1]
704                         self.setRoot(current, justSet)
705                         if not justSet:
706                                 self.setCurrentSelection(prev)
707                 return prev
708
709         def isBasePathEqual(self, ref):
710                 if len(self.servicePath) > 1 and self.servicePath[0] == ref:
711                         return True
712                 return False
713
714         def isPrevPathEqual(self, ref):
715                 length = len(self.servicePath)
716                 if length > 1 and self.servicePath[length-2] == ref:
717                         return True
718                 return False
719
720         def preEnterPath(self, refstr):
721                 return False
722
723         def showAllServices(self):
724                 if not self.pathChangeDisabled:
725                         refstr = '%s ORDER BY name'%(self.service_types)
726                         if not self.preEnterPath(refstr):
727                                 ref = eServiceReference(refstr)
728                                 currentRoot = self.getRoot()
729                                 if currentRoot is None or currentRoot != ref:
730                                         self.clearPath()
731                                         self.enterPath(ref)
732
733         def showSatellites(self):
734                 if not self.pathChangeDisabled:
735                         refstr = '%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)
736                         if not self.preEnterPath(refstr):
737                                 ref = eServiceReference(refstr)
738                                 justSet=False
739                                 prev = None
740
741                                 if self.isBasePathEqual(ref):
742                                         if self.isPrevPathEqual(ref):
743                                                 justSet=True
744                                         prev = self.pathUp(justSet)
745                                 else:
746                                         currentRoot = self.getRoot()
747                                         if currentRoot is None or currentRoot != ref:
748                                                 justSet=True
749                                                 self.clearPath()
750                                                 self.enterPath(ref, True)
751                                 if justSet:
752                                         serviceHandler = eServiceCenter.getInstance()
753                                         servicelist = serviceHandler.list(ref)
754                                         if not servicelist is None:
755                                                 while True:
756                                                         service = servicelist.getNext()
757                                                         if not service.valid(): #check if end of list
758                                                                 break
759                                                         orbpos = service.getUnsignedData(4) >> 16
760                                                         if service.getPath().find("FROM PROVIDER") != -1:
761                                                                 service_name = _("Providers")
762                                                         elif service.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
763                                                                 service_name = _("New")
764                                                         else:
765                                                                 service_name = _("Services")
766                                                         try:
767                                                                 service_name += str(' - %s'%(nimmanager.getSatDescription(orbpos)))
768                                                                 service.setName(service_name) # why we need this cast?
769                                                         except:
770                                                                 if orbpos == 0xFFFF: #Cable
771                                                                         n = ("%s (%s)") % (service_name, _("Cable"))
772                                                                 elif orbpos == 0xEEEE: #Terrestrial
773                                                                         n = ("%s (%s)") % (service_name, _("Terrestrial"))
774                                                                 else:
775                                                                         if orbpos > 1800: # west
776                                                                                 orbpos = 3600 - orbpos
777                                                                                 h = _("W")
778                                                                         else:
779                                                                                 h = _("E")
780                                                                         n = ("%s (%d.%d" + h + ")") % (service_name, orbpos / 10, orbpos % 10)
781                                                                 service.setName(n)
782                                                         self.servicelist.addService(service)
783                                                 self.servicelist.finishFill()
784                                                 if prev is not None:
785                                                         self.setCurrentSelection(prev)
786
787         def showProviders(self):
788                 if not self.pathChangeDisabled:
789                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
790                         if not self.preEnterPath(refstr):
791                                 ref = eServiceReference(refstr)
792                                 if self.isBasePathEqual(ref):
793                                         self.pathUp()
794                                 else:
795                                         currentRoot = self.getRoot()
796                                         if currentRoot is None or currentRoot != ref:
797                                                 self.clearPath()
798                                                 self.enterPath(ref)
799
800         def changeBouquet(self, direction):
801                 if not self.pathChangeDisabled:
802                         if len(self.servicePath) > 1:
803                                 #when enter satellite root list we must do some magic stuff..
804                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
805                                 if self.isBasePathEqual(ref):
806                                         self.showSatellites()
807                                 else:
808                                         self.pathUp()
809                                 if direction < 0:
810                                         self.moveUp()
811                                 else:
812                                         self.moveDown()
813                                 ref = self.getCurrentSelection()
814                                 self.enterPath(ref)
815
816         def inBouquet(self):
817                 return self.isBasePathEqual(self.bouquet_root)
818
819         def atBegin(self):
820                 return self.servicelist.atBegin()
821
822         def atEnd(self):
823                 return self.servicelist.atEnd()
824
825         def nextBouquet(self):
826                 self.changeBouquet(+1)
827
828         def prevBouquet(self):
829                 self.changeBouquet(-1)
830
831         def showFavourites(self):
832                 if not self.pathChangeDisabled:
833                         if not self.preEnterPath(self.bouquet_rootstr):
834                                 if self.isBasePathEqual(self.bouquet_root):
835                                         self.pathUp()
836                                 else:
837                                         currentRoot = self.getRoot()
838                                         if currentRoot is None or currentRoot != self.bouquet_root:
839                                                 self.clearPath()
840                                                 self.enterPath(self.bouquet_root)
841
842         def keyNumberGlobal(self, number):
843                 unichar = self.numericalTextInput.getKey(number)
844                 charstr = unichar.encode("utf-8")
845                 if len(charstr) == 1:
846                         self.servicelist.moveToChar(charstr[0])
847
848         def getRoot(self):
849                 return self.servicelist.getRoot()
850
851         def getCurrentSelection(self):
852                 return self.servicelist.getCurrent()
853
854         def setCurrentSelection(self, service):
855                 servicepath = service.getPath()
856                 pos = servicepath.find(" FROM BOUQUET")
857                 if pos != -1:
858                         if self.mode == MODE_TV:
859                                 servicepath = '(type == 1)' + servicepath[pos:]
860                         else:
861                                 servicepath = '(type == 2)' + servicepath[pos:]
862                         service.setPath(servicepath)
863                 self.servicelist.setCurrent(service)
864
865         def getBouquetList(self):
866                 bouquets = [ ]
867                 serviceHandler = eServiceCenter.getInstance()
868                 if config.usage.multibouquet.value:
869                         list = serviceHandler.list(self.bouquet_root)
870                         if list:
871                                 while True:
872                                         s = list.getNext()
873                                         if not s.valid():
874                                                 break
875                                         if (s.flags & eServiceReference.isGroup):
876                                                 continue
877                                         if (s.flags & eServiceReference.flagDirectory) == eServiceReference.flagDirectory:
878                                                 info = serviceHandler.info(s)
879                                                 if info:
880                                                         bouquets.append((info.getName(s), s))
881                                 return bouquets
882                 else:
883                         info = serviceHandler.info(self.bouquet_root)
884                         if info:
885                                 bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
886                         return bouquets
887                 return None
888
889         def getGroupList(self):
890                 groups = [ ]
891                 serviceHandler = eServiceCenter.getInstance()
892                 list = serviceHandler.list(self.bouquet_root)
893                 if list:
894                         while True:
895                                 s = list.getNext()
896                                 if not s.valid():
897                                         break
898                                 if (s.flags & eServiceReference.isGroup) and (s.flags & eServiceReference.flagDirectory) == eServiceReference.flagDirectory:
899                                         info = serviceHandler.info(s)
900                                         if info:
901                                                 groups.append((info.getName(s), s))
902                 return groups
903
904         def keyNumber0(self, num):
905                 if len(self.servicePath) > 1:
906                         self.keyGoUp()
907                 else:
908                         self.keyNumberGlobal(num)
909
910         def keyGoUp(self):
911                 if len(self.servicePath) > 1:
912                         if self.isBasePathEqual(self.bouquet_root):
913                                 self.showFavourites()
914                         else:
915                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
916                                 if self.isBasePathEqual(ref):
917                                         self.showSatellites()
918                                 else:
919                                         ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
920                                         if self.isBasePathEqual(ref):
921                                                 self.showProviders()
922                                         else:
923                                                 self.showAllServices()
924
925         def nextMarker(self):
926                 self.servicelist.moveToNextMarker()
927
928         def prevMarker(self):
929                 self.servicelist.moveToPrevMarker()
930
931 HISTORYSIZE = 20
932
933 #config for lastservice
934 config.tv = ConfigSubsection()
935 config.tv.lastservice = ConfigText()
936 config.tv.lastroot = ConfigText()
937 config.radio = ConfigSubsection()
938 config.radio.lastservice = ConfigText()
939 config.radio.lastroot = ConfigText()
940 config.servicelist = ConfigSubsection()
941 config.servicelist.lastmode = ConfigText(default = "tv")
942
943 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
944         def __init__(self, session):
945                 ChannelSelectionBase.__init__(self,session)
946                 ChannelSelectionEdit.__init__(self)
947                 ChannelSelectionEPG.__init__(self)
948
949                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
950                         {
951                                 "cancel": self.cancel,
952                                 "ok": self.channelSelected,
953                                 "keyRadio": self.setModeRadio,
954                                 "keyTV": self.setModeTv,
955                         })
956
957                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
958                         {
959                                 iPlayableService.evStart: self.__evServiceStart,
960                                 iPlayableService.evEnd: self.__evServiceEnd
961                         })
962
963                 self.lastChannelRootTimer = eTimer()
964                 self.lastChannelRootTimer.timeout.get().append(self.__onCreate)
965                 self.lastChannelRootTimer.start(100,True)
966
967                 self.history_tv = [ ]
968                 self.history_radio = [ ]
969                 self.history = self.history_tv
970                 self.history_pos = 0
971
972                 self.lastservice = config.tv.lastservice
973                 self.lastroot = config.tv.lastroot
974                 self.revertMode = None
975
976         def __evServiceStart(self):
977                 service = self.session.nav.getCurrentService()
978                 if service:
979                         info = service.info()
980                         if info:
981                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
982                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
983
984         def __evServiceEnd(self):
985                 self.servicelist.setPlayableIgnoreService(eServiceReference())
986
987         def setMode(self):
988                 self.restoreRoot()
989                 lastservice=eServiceReference(self.lastservice.value)
990                 if lastservice.valid():
991                         self.setCurrentSelection(lastservice)
992
993         def setModeTv(self):
994                 if self.revertMode is None and config.servicelist.lastmode.value == "radio":
995                         self.revertMode = MODE_RADIO
996                 self.history = self.history_tv
997                 self.lastservice = config.tv.lastservice
998                 self.lastroot = config.tv.lastroot
999                 config.servicelist.lastmode.value = "tv"
1000                 self.setTvMode()
1001                 self.setMode()
1002
1003         def setModeRadio(self):
1004                 if self.revertMode is None and config.servicelist.lastmode.value == "tv":
1005                         self.revertMode = MODE_TV
1006                 if config.usage.e1like_radio_mode.value:
1007                         self.history = self.history_radio
1008                         self.lastservice = config.radio.lastservice
1009                         self.lastroot = config.radio.lastroot
1010                         config.servicelist.lastmode.value = "radio"
1011                         self.setRadioMode()
1012                         self.setMode()
1013
1014         def __onCreate(self):
1015                 if config.usage.e1like_radio_mode.value:
1016                         if config.servicelist.lastmode.value == "tv":
1017                                 self.setModeTv()
1018                         else:
1019                                 self.setModeRadio()
1020                 else:
1021                         self.setModeTv()
1022                 lastservice=eServiceReference(self.lastservice.value)
1023                 if lastservice.valid():
1024                         self.zap()
1025
1026         def channelSelected(self):
1027                 ref = self.getCurrentSelection()
1028                 if self.movemode:
1029                         self.toggleMoveMarked()
1030                 elif (ref.flags & 7) == 7:
1031                         self.enterPath(ref)
1032                 elif self.bouquet_mark_edit:
1033                         self.doMark()
1034                 elif not (ref.flags & 64): # no marker
1035                         self.zap()
1036                         self.close(ref)
1037
1038         #called from infoBar and channelSelected
1039         def zap(self):
1040                 self.revertMode=None
1041                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1042                 nref = self.getCurrentSelection()
1043                 if ref is None or ref != nref:
1044                         self.session.nav.playService(nref)
1045                         self.saveRoot()
1046                         self.saveChannel()
1047                         config.servicelist.lastmode.save()
1048                         self.addToHistory(nref)
1049
1050         def addToHistory(self, ref):
1051                 if self.servicePath is not None:
1052                         tmp=self.servicePath[:]
1053                         tmp.append(ref)
1054                         try:
1055                                 del self.history[self.history_pos+1:]
1056                         except:
1057                                 pass
1058                         self.history.append(tmp)
1059                         hlen = len(self.history)
1060                         if hlen > HISTORYSIZE:
1061                                 del self.history[0]
1062                                 hlen -= 1
1063                         self.history_pos = hlen-1
1064
1065         def historyBack(self):
1066                 hlen = len(self.history)
1067                 if hlen > 1 and self.history_pos > 0:
1068                         self.history_pos -= 1
1069                         self.setHistoryPath()
1070
1071         def historyNext(self):
1072                 hlen = len(self.history)
1073                 if hlen > 1 and self.history_pos < (hlen-1):
1074                         self.history_pos += 1
1075                         self.setHistoryPath()
1076
1077         def setHistoryPath(self):
1078                 path = self.history[self.history_pos][:]
1079                 ref = path.pop()
1080                 del self.servicePath[:]
1081                 self.servicePath += path
1082                 self.saveRoot()
1083                 plen = len(path)
1084                 root = path[plen-1]
1085                 if self.getRoot() != root:
1086                         self.setRoot(root)
1087                 self.session.nav.playService(ref)
1088                 self.setCurrentSelection(ref)
1089                 self.saveChannel()
1090
1091         def saveRoot(self):
1092                 path = ''
1093                 for i in self.servicePath:
1094                         path += i.toString()
1095                         path += ';'
1096                 if len(path) and path != self.lastroot.value:
1097                         self.lastroot.value = path
1098                         self.lastroot.save()
1099
1100         def restoreRoot(self):
1101                 self.clearPath()
1102                 re = compile('.+?;')
1103                 tmp = re.findall(self.lastroot.value)
1104                 cnt = 0
1105                 for i in tmp:
1106                         self.servicePath.append(eServiceReference(i[:len(i)-1]))
1107                         cnt += 1
1108                 if cnt:
1109                         path = self.servicePath.pop()
1110                         self.enterPath(path)
1111                 else:
1112                         self.showFavourites()
1113                         self.saveRoot()
1114
1115         def preEnterPath(self, refstr):
1116                 if len(self.servicePath) and self.servicePath[0] != eServiceReference(refstr):
1117                         pathstr = self.lastroot.value
1118                         if pathstr is not None and pathstr.find(refstr) == 0:
1119                                 self.restoreRoot()
1120                                 lastservice=eServiceReference(self.lastservice.value)
1121                                 if lastservice.valid():
1122                                         self.setCurrentSelection(lastservice)
1123                                 return True
1124                 return False
1125
1126         def saveChannel(self):
1127                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1128                 if ref is not None:
1129                         refstr = ref.toString()
1130                 else:
1131                         refstr = ""
1132                 if refstr != self.lastservice.value:
1133                         self.lastservice.value = refstr
1134                         self.lastservice.save()
1135
1136         def setCurrentServicePath(self, path):
1137                 hlen = len(self.history)
1138                 if hlen > 0:
1139                         self.history[self.history_pos] = path
1140                 else:
1141                         self.history.append(path)
1142                 self.setHistoryPath()
1143
1144         def getCurrentServicePath(self):
1145                 hlen = len(self.history)
1146                 if hlen > 0:
1147                         return self.history[self.history_pos]
1148                 return None
1149
1150         def recallPrevService(self):
1151                 hlen = len(self.history)
1152                 if hlen > 1:
1153                         if self.history_pos == hlen-1:
1154                                 tmp = self.history[self.history_pos]
1155                                 self.history[self.history_pos] = self.history[self.history_pos-1]
1156                                 self.history[self.history_pos-1] = tmp
1157                         else:
1158                                 tmp = self.history[self.history_pos+1]
1159                                 self.history[self.history_pos+1] = self.history[self.history_pos]
1160                                 self.history[self.history_pos] = tmp
1161                         self.setHistoryPath()
1162
1163         def cancel(self):
1164                 if self.revertMode is None:
1165                         self.restoreRoot()
1166                         lastservice=eServiceReference(self.lastservice.value)
1167                         if lastservice.valid() and self.getCurrentSelection() != lastservice:
1168                                 self.setCurrentSelection(lastservice)
1169                 elif self.revertMode == MODE_TV:
1170                         self.setModeTv()
1171                 elif self.revertMode == MODE_RADIO:
1172                         self.setModeRadio()
1173                 self.revertMode = None
1174                 self.close(None)
1175
1176 from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord, InfoBarRadioText
1177
1178 class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord):
1179         def __init__(self, session):
1180                 Screen.__init__(self, session)
1181                 InfoBarEvent.__init__(self)
1182                 InfoBarServiceName.__init__(self)
1183                 InfoBarInstantRecord.__init__(self)
1184                 self["CurrentTime"] = Clock()
1185
1186 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, InfoBarRadioText):
1187
1188         ALLOW_SUSPEND = True
1189
1190         def __init__(self, session):
1191                 ChannelSelectionBase.__init__(self, session)
1192                 ChannelSelectionEdit.__init__(self)
1193                 ChannelSelectionEPG.__init__(self)
1194                 InfoBarRadioText.__init__(self)
1195
1196                 config.radio = ConfigSubsection();
1197                 config.radio.lastservice = ConfigText()
1198                 config.radio.lastroot = ConfigText()
1199                 self.onLayoutFinish.append(self.onCreate)
1200
1201                 self.info = session.instantiateDialog(RadioInfoBar)
1202
1203                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1204                         {
1205                                 "keyTV": self.closeRadio,
1206                                 "keyRadio": self.closeRadio,
1207                                 "cancel": self.closeRadio,
1208                                 "ok": self.channelSelected,
1209                         })
1210
1211                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1212                         {
1213                                 iPlayableService.evStart: self.__evServiceStart,
1214                                 iPlayableService.evEnd: self.__evServiceEnd
1215                         })
1216
1217         def __evServiceStart(self):
1218                 service = self.session.nav.getCurrentService()
1219                 if service:
1220                         info = service.info()
1221                         if info:
1222                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1223                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1224
1225         def __evServiceEnd(self):
1226                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1227
1228         def saveRoot(self):
1229                 path = ''
1230                 for i in self.servicePathRadio:
1231                         path += i.toString()
1232                         path += ';'
1233                 if len(path) and path != config.radio.lastroot.value:
1234                         config.radio.lastroot.value = path
1235                         config.radio.lastroot.save()
1236
1237         def restoreRoot(self):
1238                 self.clearPath()
1239                 re = compile('.+?;')
1240                 tmp = re.findall(config.radio.lastroot.value)
1241                 cnt = 0
1242                 for i in tmp:
1243                         self.servicePathRadio.append(eServiceReference(i[:len(i)-1]))
1244                         cnt += 1
1245                 if cnt:
1246                         path = self.servicePathRadio.pop()
1247                         self.enterPath(path)
1248                 else:
1249                         self.showFavourites()
1250                         self.saveRoot()
1251
1252         def preEnterPath(self, refstr):
1253                 if len(self.servicePathRadio) and self.servicePathRadio[0] != eServiceReference(refstr):
1254                         pathstr = config.radio.lastroot.value
1255                         if pathstr is not None and pathstr.find(refstr) == 0:
1256                                 self.restoreRoot()
1257                                 lastservice=eServiceReference(config.radio.lastservice.value)
1258                                 if lastservice.valid():
1259                                         self.setCurrentSelection(lastservice)
1260                                 return True
1261                 return False
1262
1263         def onCreate(self):
1264                 self.setRadioMode()
1265                 self.restoreRoot()
1266                 lastservice=eServiceReference(config.radio.lastservice.value)
1267                 if lastservice.valid():
1268                         self.servicelist.setCurrent(lastservice)
1269                         self.session.nav.playService(lastservice)
1270                 self.info.show()
1271
1272         def channelSelected(self): # just return selected service
1273                 ref = self.getCurrentSelection()
1274                 if self.movemode:
1275                         self.toggleMoveMarked()
1276                 elif (ref.flags & 7) == 7:
1277                         self.enterPath(ref)
1278                 elif self.bouquet_mark_edit:
1279                         self.doMark()
1280                 elif not (ref.flags & 64): # no marker
1281                         playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1282                         if playingref is None or playingref != ref:
1283                                 self.session.nav.playService(ref)
1284                                 config.radio.lastservice.value = ref.toString()
1285                                 config.radio.lastservice.save()
1286                         self.saveRoot()
1287
1288         def closeRadio(self):
1289                 self.info.hide()
1290                 #set previous tv service
1291                 lastservice=eServiceReference(config.tv.lastservice.value)
1292                 self.session.nav.playService(lastservice)
1293                 self.close(None)
1294
1295 class SimpleChannelSelection(ChannelSelectionBase):
1296         def __init__(self, session, title):
1297                 ChannelSelectionBase.__init__(self, session)
1298                 self.title = title
1299                 self.onShown.append(self.__onExecCallback)
1300
1301                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1302                         {
1303                                 "cancel": self.close,
1304                                 "ok": self.channelSelected,
1305                                 "keyRadio": self.setModeRadio,
1306                                 "keyTV": self.setModeTv,
1307                         })
1308
1309         def __onExecCallback(self):
1310                 self.setTitle(self.title)
1311                 self.setModeTv()
1312
1313         def channelSelected(self): # just return selected service
1314                 ref = self.getCurrentSelection()
1315                 if (ref.flags & 7) == 7:
1316                         self.enterPath(ref)
1317                 elif not (ref.flags & 64):
1318                         ref = self.getCurrentSelection()
1319                         self.close(ref)
1320
1321         def setModeTv(self):
1322                 self.setTvMode()
1323                 self.showFavourites()
1324
1325         def setModeRadio(self):
1326                 self.setRadioMode()
1327                 self.showFavourites()