more changes for service groups (replacement for zapping alternatives
[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                                 flags = csel.getCurrentSelection().flags
82                                 isPlayable = not ((flags & eServiceReference.isMarker) or (flags & eServiceReference.isDirectory))
83                                 if isPlayable:
84                                         if config.ParentalControl.configured.value:
85                                                 if parentalControl.getProtectionLevel(csel.getCurrentSelection().toCompareString()) == -1:
86                                                         menu.append((_("add to parental protection"), boundFunction(self.addParentalProtection, csel.getCurrentSelection())))
87                                                 else:
88                                                         menu.append((_("remove from parental protection"), boundFunction(self.removeParentalProtection, csel.getCurrentSelection())))
89                                         if haveBouquets:
90                                                 menu.append((_("add service to bouquet"), self.addServiceToBouquetSelected))
91                                         else:
92                                                 menu.append((_("add service to favourites"), self.addServiceToBouquetSelected))
93                                 else:
94                                         if haveBouquets:
95                                                 if not inBouquet and current_sel_path.find("PROVIDERS") == -1:
96                                                         menu.append((_("copy to bouquets"), self.copyCurrentToBouquetList))
97                                         if current_sel_path.find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
98                                                 menu.append((_("remove all new found flags"), self.removeAllNewFoundFlags))
99                                 if inBouquet:
100                                         menu.append((_("remove entry"), self.removeCurrentService))
101                                 if current_root is not None and current_root.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
102                                         menu.append((_("remove new found flag"), self.removeNewFoundFlag))
103                         else:
104                                         menu.append((_("add bouquet"), self.showBouquetInputBox))
105                                         menu.append((_("remove entry"), self.removeBouquet))
106
107                 if inBouquet: # current list is editable?
108                         if not csel.bouquet_mark_edit:
109                                 if not csel.movemode:
110                                         menu.append((_("add marker"), self.showMarkerInputBox))
111                                         menu.append((_("enable move mode"), self.toggleMoveMode))
112                                         if not inBouquetRootList:
113                                                 if haveBouquets:
114                                                         menu.append((_("enable bouquet edit"), self.bouquetMarkStart))
115                                                 else:
116                                                         menu.append((_("enable favourite edit"), self.bouquetMarkStart))
117                                 else:
118                                         menu.append((_("disable move mode"), self.toggleMoveMode))
119                         elif not inBouquetRootList:
120                                 if haveBouquets:
121                                         menu.append((_("end bouquet edit"), self.bouquetMarkEnd))
122                                         menu.append((_("abort bouquet edit"), self.bouquetMarkAbort))
123                                 else:
124                                         menu.append((_("end favourites edit"), self.bouquetMarkEnd))
125                                         menu.append((_("abort favourites edit"), self.bouquetMarkAbort))
126
127                 menu.append((_("back"), self.cancelClick))
128                 self["menu"] = MenuList(menu)
129
130         def okbuttonClick(self):
131                 self["menu"].getCurrent()[1]()
132
133         def cancelClick(self):
134                 self.close(False)
135                 
136         def showBouquetInputBox(self):
137                 self.session.openWithCallback(self.bouquetInputCallback, InputBox, title=_("Please enter a name for the new bouquet"), text="bouquetname", maxSize=False, type=Input.TEXT)
138
139         def bouquetInputCallback(self, bouquet):
140                 if bouquet is not None:
141                         self.csel.addBouquet(bouquet, None)
142                 self.close()
143
144         def addParentalProtection(self, service):
145                 parentalControl.protectService(service.toCompareString())
146                 self.close()
147
148         def removeParentalProtection(self, service):
149                 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"))
150
151         def pinEntered(self, service, result):
152                 if result:
153                         parentalControl.unProtectService(service)
154                         self.close()
155                 else:
156                         self.session.openWithCallback(self.close, MessageBox, _("The pin code you entered is wrong."), MessageBox.TYPE_ERROR)
157
158         def addServiceToBouquetSelected(self):
159                 bouquets = self.csel.getBouquetList()
160                 if bouquets is None:
161                         cnt = 0
162                 else:
163                         cnt = len(bouquets)
164                 if cnt > 1: # show bouquet list
165                         self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, bouquets, self.addCurrentServiceToBouquet)
166                 elif cnt == 1: # add to only one existing bouquet
167                         self.addCurrentServiceToBouquet(bouquets[0][1])
168
169         def bouquetSelClosed(self, recursive):
170                 self.bsel = None
171                 if recursive:
172                         self.close(False)
173
174         def copyCurrentToBouquetList(self):
175                 self.csel.copyCurrentToBouquetList()
176                 self.close()
177
178         def removeBouquet(self):
179                 self.csel.removeBouquet()
180                 self.close()
181
182         def showMarkerInputBox(self):
183                 self.session.openWithCallback(self.markerInputCallback, InputBox, title=_("Please enter a name for the new marker"), text="markername", maxSize=False, type=Input.TEXT)
184
185         def markerInputCallback(self, marker):
186                 if marker is not None:
187                         self.csel.addMarker(marker)
188                 self.close()
189
190         def addCurrentServiceToBouquet(self, dest):
191                 self.csel.addServiceToBouquet(dest)
192                 if self.bsel is not None:
193                         self.bsel.close(True)
194                 else:
195                         self.close(True) # close bouquet selection
196
197         def removeCurrentService(self):
198                 self.csel.removeCurrentService()
199                 self.close()
200
201         def toggleMoveMode(self):
202                 self.csel.toggleMoveMode()
203                 self.close()
204
205         def bouquetMarkStart(self):
206                 self.csel.startMarkedEdit()
207                 self.close()
208
209         def bouquetMarkEnd(self):
210                 self.csel.endMarkedEdit(abort=False)
211                 self.close()
212
213         def bouquetMarkAbort(self):
214                 self.csel.endMarkedEdit(abort=True)
215                 self.close()
216
217         def removeNewFoundFlag(self):
218                 eDVBDB.getInstance().removeFlag(self.csel.getCurrentSelection(), FLAG_SERVICE_NEW_FOUND)
219                 self.close()
220
221         def removeAllNewFoundFlags(self):
222                 curpath = self.csel.getCurrentSelection().getPath()
223                 idx = curpath.find("satellitePosition == ")
224                 if idx != -1:
225                         tmp = curpath[idx+21:]
226                         idx = tmp.find(')')
227                         if idx != -1:
228                                 satpos = int(tmp[:idx])
229                                 eDVBDB.getInstance().removeFlags(FLAG_SERVICE_NEW_FOUND, -1, -1, -1, satpos)
230                 self.close()
231
232 class ChannelSelectionEPG:
233         def __init__(self):
234                 self["ChannelSelectEPGActions"] = ActionMap(["ChannelSelectEPGActions"],
235                         {
236                                 "showEPGList": self.showEPGList,
237                         })
238
239         def showEPGList(self):
240                 ref=self.getCurrentSelection()
241                 ptr=eEPGCache.getInstance()
242                 if ptr.startTimeQuery(ref) != -1:
243                         self.session.open(EPGSelection, ref)
244                 else:
245                         print 'no epg for service', ref.toString()
246
247 class ChannelSelectionEdit:
248         def __init__(self):
249                 self.entry_marked = False
250                 self.movemode = False
251                 self.bouquet_mark_edit = False
252                 self.mutableList = None
253                 self.__marked = [ ]
254                 self.saved_title = None
255                 self.saved_root = None
256
257                 class ChannelSelectionEditActionMap(ActionMap):
258                         def __init__(self, csel, contexts = [ ], actions = { }, prio=0):
259                                 ActionMap.__init__(self, contexts, actions, prio)
260                                 self.csel = csel
261
262                         def action(self, contexts, action):
263                                 if action == "cancel":
264                                         self.csel.handleEditCancel()
265                                         return 0 # fall-trough
266                                 elif action == "ok":
267                                         return 0 # fall-trough
268                                 else:
269                                         return ActionMap.action(self, contexts, action)
270
271                 self["ChannelSelectEditActions"] = ChannelSelectionEditActionMap(self, ["ChannelSelectEditActions", "OkCancelActions"],
272                         {
273                                 "contextMenu": self.doContext,
274                         })
275
276         def getMutableList(self, root=eServiceReference()):
277                 if not self.mutableList is None:
278                         return self.mutableList
279                 serviceHandler = eServiceCenter.getInstance()
280                 if not root.valid():
281                         root=self.getRoot()
282                 list = root and serviceHandler.list(root)
283                 if list is not None:
284                         return list.startEdit()
285                 return None
286
287         def buildBouquetID(self, str):
288                 tmp = str.lower()
289                 name = ''
290                 for c in tmp:
291                         if (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9'):
292                                 name += c
293                         else:
294                                 name += '_'
295                 return name
296
297         def addMarker(self, name):
298                 current = self.servicelist.getCurrent()
299                 mutableList = self.getMutableList()
300                 cnt = 0
301                 while mutableList:
302                         str = '1:64:%d:0:0:0:0:0:0:0::%s'%(cnt, name)
303                         ref = eServiceReference(str)
304                         if current and current.valid():
305                                 if not mutableList.addService(ref, current):
306                                         self.servicelist.addService(ref, True)
307                                         mutableList.flushChanges()
308                                         break
309                         elif not mutableList.addService(ref):
310                                 self.servicelist.addService(ref, True)
311                                 mutableList.flushChanges()
312                                 break
313                         cnt+=1
314
315         def addBouquet(self, bName, services):
316                 serviceHandler = eServiceCenter.getInstance()
317                 mutableBouquetList = serviceHandler.list(self.bouquet_root).startEdit()
318                 if mutableBouquetList:
319                         if self.mode == MODE_TV:
320                                 bName += " (TV)"
321                                 str = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET \"userbouquet.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(bName))
322                         else:
323                                 bName += " (Radio)"
324                                 str = '1:7:2:0:0:0:0:0:0:0:(type == 2) FROM BOUQUET \"userbouquet.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(bName))
325                         new_bouquet_ref = eServiceReference(str)
326                         if not mutableBouquetList.addService(new_bouquet_ref):
327                                 mutableBouquetList.flushChanges()
328                                 eDVBDB.getInstance().reloadBouquets()
329                                 mutableBouquet = serviceHandler.list(new_bouquet_ref).startEdit()
330                                 if mutableBouquet:
331                                         mutableBouquet.setListName(bName)
332                                         if services is not None:
333                                                 for service in services:
334                                                         if mutableBouquet.addService(service):
335                                                                 print "add", service.toString(), "to new bouquet failed"
336                                         mutableBouquet.flushChanges()
337                                 else:
338                                         print "get mutable list for new created bouquet failed"
339                                 # do some voodoo to check if current_root is equal to bouquet_root
340                                 cur_root = self.getRoot();
341                                 str1 = cur_root.toString()
342                                 pos1 = str1.find("FROM BOUQUET")
343                                 pos2 = self.bouquet_rootstr.find("FROM BOUQUET")
344                                 if pos1 != -1 and pos2 != -1 and str1[pos1:] == self.bouquet_rootstr[pos2:]:
345                                         self.servicelist.addService(new_bouquet_ref)
346                         else:
347                                 print "add", str, "to bouquets failed"
348                 else:
349                         print "bouquetlist is not editable"
350
351         def copyCurrentToBouquetList(self):
352                 provider = ServiceReference(self.getCurrentSelection())
353                 providerName = provider.getServiceName()
354                 serviceHandler = eServiceCenter.getInstance()
355                 services = serviceHandler.list(provider.ref)
356                 self.addBouquet(providerName, services and services.getContent('R', True))
357
358         def removeBouquet(self):
359                 refstr = self.getCurrentSelection().toString()
360                 self.bouquetNumOffsetCache = { }
361                 pos = refstr.find('FROM BOUQUET "')
362                 filename = None
363                 if pos != -1:
364                         refstr = refstr[pos+14:]
365                         pos = refstr.find('"')
366                         if pos != -1:
367                                 filename = '/etc/enigma2/' + refstr[:pos] # FIXMEEE !!! HARDCODED /etc/enigma2
368                 self.removeCurrentService()
369                 try:
370                         if filename is not None:
371                                 remove(filename)
372                 except OSError:
373                         print "error during remove of", filename
374
375 #  multiple marked entry stuff ( edit mode, later multiepg selection )
376         def startMarkedEdit(self):
377                 self.mutableList = self.getMutableList()
378                 # add all services from the current list to internal marked set in listboxservicecontent
379                 self.clearMarks() # this clears the internal marked set in the listboxservicecontent
380                 self.saved_title = self.instance.getTitle()
381                 pos = self.saved_title.find(')')
382                 new_title = self.saved_title[:pos+1]
383                 if config.usage.multibouquet.value:
384                         new_title += ' ' + _("[bouquet edit]")
385                 else:
386                         new_title += ' ' + _("[favourite edit]")
387                 self.setTitle(new_title)
388                 self.bouquet_mark_edit = True
389                 self.__marked = self.servicelist.getRootServices()
390                 for x in self.__marked:
391                         self.servicelist.addMarked(eServiceReference(x))
392                 self.savedPath = self.servicePath[:]
393                 self.showAllServices()
394
395         def endMarkedEdit(self, abort):
396                 if not abort and self.mutableList is not None:
397                         self.bouquetNumOffsetCache = { }
398                         new_marked = set(self.servicelist.getMarked())
399                         old_marked = set(self.__marked)
400                         removed = old_marked - new_marked
401                         added = new_marked - old_marked
402                         changed = False
403                         for x in removed:
404                                 changed = True
405                                 self.mutableList.removeService(eServiceReference(x))
406                         for x in added:
407                                 changed = True
408                                 self.mutableList.addService(eServiceReference(x))
409                         if changed:
410                                 self.mutableList.flushChanges()
411                 self.__marked = []
412                 self.clearMarks()
413                 self.bouquet_mark_edit = False
414                 self.mutableList = None
415                 self.setTitle(self.saved_title)
416                 self.saved_title = None
417                 # self.servicePath is just a reference to servicePathTv or Radio...
418                 # so we never ever do use the asignment operator in self.servicePath
419                 del self.servicePath[:] # remove all elements
420                 self.servicePath += self.savedPath # add saved elements
421                 del self.savedPath
422                 self.setRoot(self.servicePath[len(self.servicePath)-1])
423
424         def clearMarks(self):
425                 self.servicelist.clearMarks()
426
427         def doMark(self):
428                 ref = self.servicelist.getCurrent()
429                 if self.servicelist.isMarked(ref):
430                         self.servicelist.removeMarked(ref)
431                 else:
432                         self.servicelist.addMarked(ref)
433
434         def removeCurrentService(self):
435                 ref = self.servicelist.getCurrent()
436                 mutableList = self.getMutableList()
437                 if ref.valid() and mutableList is not None:
438                         if not mutableList.removeService(ref):
439                                 self.bouquetNumOffsetCache = { }
440                                 mutableList.flushChanges() #FIXME dont flush on each single removed service
441                                 self.servicelist.removeCurrent()
442
443         def addServiceToBouquet(self, dest, service=None):
444                 mutableList = self.getMutableList(dest)
445                 if not mutableList is None:
446                         if service is None: #use current selected service
447                                 service = self.servicelist.getCurrent()
448                         if not mutableList.addService(service):
449                                 self.bouquetNumOffsetCache = { }
450                                 mutableList.flushChanges()
451                                 # do some voodoo to check if current_root is equal to dest
452                                 cur_root = self.getRoot();
453                                 str1 = cur_root.toString()
454                                 str2 = dest.toString()
455                                 pos1 = str1.find("FROM BOUQUET")
456                                 pos2 = str2.find("FROM BOUQUET")
457                                 if pos1 != -1 and pos2 != -1 and str1[pos1:] == str2[pos2:]:
458                                         self.servicelist.addService(service)
459
460         def toggleMoveMode(self):
461                 if self.movemode:
462                         if self.entry_marked:
463                                 self.toggleMoveMarked() # unmark current entry
464                         self.movemode = False
465                         self.pathChangeDisabled = False # re-enable path change
466                         self.mutableList.flushChanges() # FIXME add check if changes was made
467                         self.mutableList = None
468                         self.setTitle(self.saved_title)
469                         self.saved_title = None
470                         if self.getRoot() == self.bouquet_root:
471                                 self.bouquetNumOffsetCache = { }
472                 else:
473                         self.mutableList = self.getMutableList()
474                         self.movemode = True
475                         self.pathChangeDisabled = True # no path change allowed in movemode
476                         self.saved_title = self.instance.getTitle()
477                         new_title = self.saved_title
478                         pos = self.saved_title.find(')')
479                         new_title = self.saved_title[:pos+1] + ' ' + _("[move mode]") + self.saved_title[pos+1:]
480                         self.setTitle(new_title);
481
482         def handleEditCancel(self):
483                 if self.movemode: #movemode active?
484                         self.channelSelected() # unmark
485                         self.toggleMoveMode() # disable move mode
486                 elif self.bouquet_mark_edit:
487                         self.endMarkedEdit(True) # abort edit mode
488
489         def toggleMoveMarked(self):
490                 if self.entry_marked:
491                         self.servicelist.setCurrentMarked(False)
492                         self.entry_marked = False
493                 else:
494                         self.servicelist.setCurrentMarked(True)
495                         self.entry_marked = True
496
497         def doContext(self):
498                 self.session.open(ChannelContextMenu, self)
499
500 MODE_TV = 0
501 MODE_RADIO = 1
502
503 # this makes it much simple to implement a selectable radio or tv mode :)
504 service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 195) || (type == 25)'
505 service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2)'
506
507 class ChannelSelectionBase(Screen):
508         def __init__(self, session):
509                 Screen.__init__(self, session)
510
511                 self["key_red"] = Button(_("All"))
512                 self["key_green"] = Button(_("Satellites"))
513                 self["key_yellow"] = Button(_("Provider"))
514                 self["key_blue"] = Button(_("Favourites"))
515
516                 self["list"] = ServiceList()
517                 self.servicelist = self["list"]
518
519                 self.numericalTextInput = NumericalTextInput()
520                 self.numericalTextInput.setUseableChars(u'1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ')
521
522                 self.servicePathTV = [ ]
523                 self.servicePathRadio = [ ]
524                 self.servicePath = [ ]
525
526                 self.mode = MODE_TV
527
528                 self.pathChangeDisabled = False
529
530                 self.bouquetNumOffsetCache = { }
531
532                 self["ChannelSelectBaseActions"] = NumberActionMap(["ChannelSelectBaseActions", "NumberActions"],
533                         {
534                                 "showFavourites": self.showFavourites,
535                                 "showAllServices": self.showAllServices,
536                                 "showProviders": self.showProviders,
537                                 "showSatellites": self.showSatellites,
538                                 "nextBouquet": self.nextBouquet,
539                                 "prevBouquet": self.prevBouquet,
540                                 "nextMarker": self.nextMarker,
541                                 "prevMarker": self.prevMarker,
542                                 "1": self.keyNumberGlobal,
543                                 "2": self.keyNumberGlobal,
544                                 "3": self.keyNumberGlobal,
545                                 "4": self.keyNumberGlobal,
546                                 "5": self.keyNumberGlobal,
547                                 "6": self.keyNumberGlobal,
548                                 "7": self.keyNumberGlobal,
549                                 "8": self.keyNumberGlobal,
550                                 "9": self.keyNumberGlobal,
551                                 "0": self.keyNumber0
552                         })
553                 self.recallBouquetMode()
554
555         def appendDVBTypes(self, ref):
556                 path = ref.getPath()
557                 pos = path.find(' FROM BOUQUET')
558                 if pos != -1:
559                         return eServiceReference(self.service_types + path[pos:])
560                 return ref
561
562         def getBouquetNumOffset(self, bouquet):
563                 if not config.usage.multibouquet.value:
564                         return 0
565                 bouquet = self.appendDVBTypes(bouquet)
566                 str = bouquet.toString()
567                 offsetCount = 0
568                 if not self.bouquetNumOffsetCache.has_key(str):
569                         serviceHandler = eServiceCenter.getInstance()
570                         bouquetlist = serviceHandler.list(self.bouquet_root)
571                         if not bouquetlist is None:
572                                 while True:
573                                         bouquetIterator = self.appendDVBTypes(bouquetlist.getNext())
574                                         if not bouquetIterator.valid(): #end of list
575                                                 break
576                                         self.bouquetNumOffsetCache[bouquetIterator.toString()]=offsetCount
577                                         if not (bouquetIterator.flags & eServiceReference.isDirectory):
578                                                 continue
579                                         servicelist = serviceHandler.list(bouquetIterator)
580                                         if not servicelist is None:
581                                                 while True:
582                                                         serviceIterator = servicelist.getNext()
583                                                         if not serviceIterator.valid(): #check if end of list
584                                                                 break
585                                                         if serviceIterator.flags: #playable services have no flags
586                                                                 continue
587                                                         offsetCount += 1
588                 return self.bouquetNumOffsetCache.get(str, offsetCount)
589
590         def recallBouquetMode(self):
591                 if self.mode == MODE_TV:
592                         self.service_types = service_types_tv
593                         if config.usage.multibouquet.value:
594                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.tv" ORDER BY bouquet'
595                         else:
596                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)
597                 else:
598                         self.service_types = service_types_radio
599                         if config.usage.multibouquet.value:
600                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.radio" ORDER BY bouquet'
601                         else:
602                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(self.service_types)
603                 self.bouquet_root = eServiceReference(self.bouquet_rootstr)
604
605         def setTvMode(self):
606                 self.mode = MODE_TV
607                 self.servicePath = self.servicePathTV
608                 self.recallBouquetMode()
609                 title = self.instance.getTitle()
610                 pos = title.find(" (")
611                 if pos != -1:
612                         title = title[:pos]
613                 title += " (TV)"
614                 self.setTitle(title)
615
616         def setRadioMode(self):
617                 self.mode = MODE_RADIO
618                 self.servicePath = self.servicePathRadio
619                 self.recallBouquetMode()
620                 title = self.instance.getTitle()
621                 pos = title.find(" (")
622                 if pos != -1:
623                         title = title[:pos]
624                 title += " (Radio)"
625                 self.setTitle(title)
626
627         def setRoot(self, root, justSet=False):
628                 path = root.getPath()
629                 inBouquetRootList = path.find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
630                 pos = path.find(' FROM BOUQUET')
631                 isBouquet = pos != -1
632                 if not inBouquetRootList and isBouquet:
633                         self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
634                         self.servicelist.setNumberOffset(self.getBouquetNumOffset(root))
635                         refstr = self.service_types + path[pos:]
636                         root = eServiceReference(refstr)
637                 else:
638                         self.servicelist.setMode(ServiceList.MODE_NORMAL)
639                 self.servicelist.setRoot(root, justSet)
640                 self.buildTitleString()
641
642         def removeModeStr(self, str):
643                 if self.mode == MODE_TV:
644                         pos = str.find(' (TV)')
645                 else:
646                         pos = str.find(' (Radio)')
647                 if pos != -1:
648                         return str[:pos]
649                 return str
650
651         def getServiceName(self, ref):
652                 str = self.removeModeStr(ServiceReference(ref).getServiceName())
653                 if not len(str):
654                         pathstr = ref.getPath()
655                         if pathstr.find('FROM PROVIDERS') != -1:
656                                 return _("Provider")
657                         if pathstr.find('FROM SATELLITES') != -1:
658                                 return _("Satellites")
659                         if pathstr.find(') ORDER BY name') != -1:
660                                 return _("All")
661                 return str
662
663         def buildTitleString(self):
664                 titleStr = self.instance.getTitle()
665                 pos = titleStr.find(']')
666                 if pos == -1:
667                         pos = titleStr.find(')')
668                 if pos != -1:
669                         titleStr = titleStr[:pos+1]
670                         Len = len(self.servicePath)
671                         if Len > 0:
672                                 base_ref = self.servicePath[0]
673                                 if Len > 1:
674                                         end_ref = self.servicePath[Len-1]
675                                 else:
676                                         end_ref = None
677                                 nameStr = self.getServiceName(base_ref)
678                                 titleStr += ' ' + nameStr
679                                 if end_ref is not None:
680                                         if Len > 2:
681                                                 titleStr += '/../'
682                                         else:
683                                                 titleStr += '/'
684                                         nameStr = self.getServiceName(end_ref)
685                                         titleStr += nameStr
686                                 self.setTitle(titleStr)
687
688         def moveUp(self):
689                 self.servicelist.moveUp()
690
691         def moveDown(self):
692                 self.servicelist.moveDown()
693
694         def clearPath(self):
695                 del self.servicePath[:]
696
697         def enterPath(self, ref, justSet=False):
698                 self.servicePath.append(ref)
699                 self.setRoot(ref, justSet)
700
701         def pathUp(self, justSet=False):
702                 prev = self.servicePath.pop()
703                 length = len(self.servicePath)
704                 if length:
705                         current = self.servicePath[length-1]
706                         self.setRoot(current, justSet)
707                         if not justSet:
708                                 self.setCurrentSelection(prev)
709                 return prev
710
711         def isBasePathEqual(self, ref):
712                 if len(self.servicePath) > 1 and self.servicePath[0] == ref:
713                         return True
714                 return False
715
716         def isPrevPathEqual(self, ref):
717                 length = len(self.servicePath)
718                 if length > 1 and self.servicePath[length-2] == ref:
719                         return True
720                 return False
721
722         def preEnterPath(self, refstr):
723                 return False
724
725         def showAllServices(self):
726                 if not self.pathChangeDisabled:
727                         refstr = '%s ORDER BY name'%(self.service_types)
728                         if not self.preEnterPath(refstr):
729                                 ref = eServiceReference(refstr)
730                                 currentRoot = self.getRoot()
731                                 if currentRoot is None or currentRoot != ref:
732                                         self.clearPath()
733                                         self.enterPath(ref)
734
735         def showSatellites(self):
736                 if not self.pathChangeDisabled:
737                         refstr = '%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)
738                         if not self.preEnterPath(refstr):
739                                 ref = eServiceReference(refstr)
740                                 justSet=False
741                                 prev = None
742
743                                 if self.isBasePathEqual(ref):
744                                         if self.isPrevPathEqual(ref):
745                                                 justSet=True
746                                         prev = self.pathUp(justSet)
747                                 else:
748                                         currentRoot = self.getRoot()
749                                         if currentRoot is None or currentRoot != ref:
750                                                 justSet=True
751                                                 self.clearPath()
752                                                 self.enterPath(ref, True)
753                                 if justSet:
754                                         serviceHandler = eServiceCenter.getInstance()
755                                         servicelist = serviceHandler.list(ref)
756                                         if not servicelist is None:
757                                                 while True:
758                                                         service = servicelist.getNext()
759                                                         if not service.valid(): #check if end of list
760                                                                 break
761                                                         orbpos = service.getUnsignedData(4) >> 16
762                                                         if service.getPath().find("FROM PROVIDER") != -1:
763                                                                 service_name = _("Providers")
764                                                         elif service.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
765                                                                 service_name = _("New")
766                                                         else:
767                                                                 service_name = _("Services")
768                                                         try:
769                                                                 service_name += str(' - %s'%(nimmanager.getSatDescription(orbpos)))
770                                                                 service.setName(service_name) # why we need this cast?
771                                                         except:
772                                                                 if orbpos == 0xFFFF: #Cable
773                                                                         n = ("%s (%s)") % (service_name, _("Cable"))
774                                                                 elif orbpos == 0xEEEE: #Terrestrial
775                                                                         n = ("%s (%s)") % (service_name, _("Terrestrial"))
776                                                                 else:
777                                                                         if orbpos > 1800: # west
778                                                                                 orbpos = 3600 - orbpos
779                                                                                 h = _("W")
780                                                                         else:
781                                                                                 h = _("E")
782                                                                         n = ("%s (%d.%d" + h + ")") % (service_name, orbpos / 10, orbpos % 10)
783                                                                 service.setName(n)
784                                                         self.servicelist.addService(service)
785                                                 self.servicelist.finishFill()
786                                                 if prev is not None:
787                                                         self.setCurrentSelection(prev)
788
789         def showProviders(self):
790                 if not self.pathChangeDisabled:
791                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
792                         if not self.preEnterPath(refstr):
793                                 ref = eServiceReference(refstr)
794                                 if self.isBasePathEqual(ref):
795                                         self.pathUp()
796                                 else:
797                                         currentRoot = self.getRoot()
798                                         if currentRoot is None or currentRoot != ref:
799                                                 self.clearPath()
800                                                 self.enterPath(ref)
801
802         def changeBouquet(self, direction):
803                 if not self.pathChangeDisabled:
804                         if len(self.servicePath) > 1:
805                                 #when enter satellite root list we must do some magic stuff..
806                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
807                                 if self.isBasePathEqual(ref):
808                                         self.showSatellites()
809                                 else:
810                                         self.pathUp()
811                                 if direction < 0:
812                                         self.moveUp()
813                                 else:
814                                         self.moveDown()
815                                 ref = self.getCurrentSelection()
816                                 self.enterPath(ref)
817
818         def inBouquet(self):
819                 return self.isBasePathEqual(self.bouquet_root)
820
821         def atBegin(self):
822                 return self.servicelist.atBegin()
823
824         def atEnd(self):
825                 return self.servicelist.atEnd()
826
827         def nextBouquet(self):
828                 self.changeBouquet(+1)
829
830         def prevBouquet(self):
831                 self.changeBouquet(-1)
832
833         def showFavourites(self):
834                 if not self.pathChangeDisabled:
835                         if not self.preEnterPath(self.bouquet_rootstr):
836                                 if self.isBasePathEqual(self.bouquet_root):
837                                         self.pathUp()
838                                 else:
839                                         currentRoot = self.getRoot()
840                                         if currentRoot is None or currentRoot != self.bouquet_root:
841                                                 self.clearPath()
842                                                 self.enterPath(self.bouquet_root)
843
844         def keyNumberGlobal(self, number):
845                 unichar = self.numericalTextInput.getKey(number)
846                 charstr = unichar.encode("utf-8")
847                 if len(charstr) == 1:
848                         self.servicelist.moveToChar(charstr[0])
849
850         def getRoot(self):
851                 return self.servicelist.getRoot()
852
853         def getCurrentSelection(self):
854                 return self.servicelist.getCurrent()
855
856         def setCurrentSelection(self, service):
857                 servicepath = service.getPath()
858                 pos = servicepath.find(" FROM BOUQUET")
859                 if pos != -1:
860                         if self.mode == MODE_TV:
861                                 servicepath = '(type == 1)' + servicepath[pos:]
862                         else:
863                                 servicepath = '(type == 2)' + servicepath[pos:]
864                         service.setPath(servicepath)
865                 self.servicelist.setCurrent(service)
866
867         def getBouquetList(self):
868                 bouquets = [ ]
869                 serviceHandler = eServiceCenter.getInstance()
870                 if config.usage.multibouquet.value:
871                         list = serviceHandler.list(self.bouquet_root)
872                         if list:
873                                 while True:
874                                         s = list.getNext()
875                                         if not s.valid():
876                                                 break
877                                         if s.flags & eServiceReference.isDirectory:
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.mustDescent):
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(nref)
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(ref)
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, ref):
1127                 if ref is not None:
1128                         refstr = ref.toString()
1129                 else:
1130                         refstr = ""
1131                 if refstr != self.lastservice.value:
1132                         self.lastservice.value = refstr
1133                         self.lastservice.save()
1134
1135         def setCurrentServicePath(self, path):
1136                 hlen = len(self.history)
1137                 if hlen > 0:
1138                         self.history[self.history_pos] = path
1139                 else:
1140                         self.history.append(path)
1141                 self.setHistoryPath()
1142
1143         def getCurrentServicePath(self):
1144                 hlen = len(self.history)
1145                 if hlen > 0:
1146                         return self.history[self.history_pos]
1147                 return None
1148
1149         def recallPrevService(self):
1150                 hlen = len(self.history)
1151                 if hlen > 1:
1152                         if self.history_pos == hlen-1:
1153                                 tmp = self.history[self.history_pos]
1154                                 self.history[self.history_pos] = self.history[self.history_pos-1]
1155                                 self.history[self.history_pos-1] = tmp
1156                         else:
1157                                 tmp = self.history[self.history_pos+1]
1158                                 self.history[self.history_pos+1] = self.history[self.history_pos]
1159                                 self.history[self.history_pos] = tmp
1160                         self.setHistoryPath()
1161
1162         def cancel(self):
1163                 if self.revertMode is None:
1164                         self.restoreRoot()
1165                         lastservice=eServiceReference(self.lastservice.value)
1166                         if lastservice.valid() and self.getCurrentSelection() != lastservice:
1167                                 self.setCurrentSelection(lastservice)
1168                 elif self.revertMode == MODE_TV:
1169                         self.setModeTv()
1170                 elif self.revertMode == MODE_RADIO:
1171                         self.setModeRadio()
1172                 self.revertMode = None
1173                 self.close(None)
1174
1175 from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord, InfoBarRadioText
1176
1177 class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord):
1178         def __init__(self, session):
1179                 Screen.__init__(self, session)
1180                 InfoBarEvent.__init__(self)
1181                 InfoBarServiceName.__init__(self)
1182                 InfoBarInstantRecord.__init__(self)
1183                 self["CurrentTime"] = Clock()
1184
1185 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, InfoBarRadioText):
1186
1187         ALLOW_SUSPEND = True
1188
1189         def __init__(self, session):
1190                 ChannelSelectionBase.__init__(self, session)
1191                 ChannelSelectionEdit.__init__(self)
1192                 ChannelSelectionEPG.__init__(self)
1193                 InfoBarRadioText.__init__(self)
1194
1195                 config.radio = ConfigSubsection();
1196                 config.radio.lastservice = ConfigText()
1197                 config.radio.lastroot = ConfigText()
1198                 self.onLayoutFinish.append(self.onCreate)
1199
1200                 self.info = session.instantiateDialog(RadioInfoBar)
1201
1202                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1203                         {
1204                                 "keyTV": self.closeRadio,
1205                                 "keyRadio": self.closeRadio,
1206                                 "cancel": self.closeRadio,
1207                                 "ok": self.channelSelected,
1208                         })
1209
1210                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1211                         {
1212                                 iPlayableService.evStart: self.__evServiceStart,
1213                                 iPlayableService.evEnd: self.__evServiceEnd
1214                         })
1215
1216         def __evServiceStart(self):
1217                 service = self.session.nav.getCurrentService()
1218                 if service:
1219                         info = service.info()
1220                         if info:
1221                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1222                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1223
1224         def __evServiceEnd(self):
1225                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1226
1227         def saveRoot(self):
1228                 path = ''
1229                 for i in self.servicePathRadio:
1230                         path += i.toString()
1231                         path += ';'
1232                 if len(path) and path != config.radio.lastroot.value:
1233                         config.radio.lastroot.value = path
1234                         config.radio.lastroot.save()
1235
1236         def restoreRoot(self):
1237                 self.clearPath()
1238                 re = compile('.+?;')
1239                 tmp = re.findall(config.radio.lastroot.value)
1240                 cnt = 0
1241                 for i in tmp:
1242                         self.servicePathRadio.append(eServiceReference(i[:len(i)-1]))
1243                         cnt += 1
1244                 if cnt:
1245                         path = self.servicePathRadio.pop()
1246                         self.enterPath(path)
1247                 else:
1248                         self.showFavourites()
1249                         self.saveRoot()
1250
1251         def preEnterPath(self, refstr):
1252                 if len(self.servicePathRadio) and self.servicePathRadio[0] != eServiceReference(refstr):
1253                         pathstr = config.radio.lastroot.value
1254                         if pathstr is not None and pathstr.find(refstr) == 0:
1255                                 self.restoreRoot()
1256                                 lastservice=eServiceReference(config.radio.lastservice.value)
1257                                 if lastservice.valid():
1258                                         self.setCurrentSelection(lastservice)
1259                                 return True
1260                 return False
1261
1262         def onCreate(self):
1263                 self.setRadioMode()
1264                 self.restoreRoot()
1265                 lastservice=eServiceReference(config.radio.lastservice.value)
1266                 if lastservice.valid():
1267                         self.servicelist.setCurrent(lastservice)
1268                         self.session.nav.playService(lastservice)
1269                 self.info.show()
1270
1271         def channelSelected(self): # just return selected service
1272                 ref = self.getCurrentSelection()
1273                 if self.movemode:
1274                         self.toggleMoveMarked()
1275                 elif (ref.flags & 7) == 7:
1276                         self.enterPath(ref)
1277                 elif self.bouquet_mark_edit:
1278                         self.doMark()
1279                 elif not (ref.flags & 64): # no marker
1280                         playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1281                         if playingref is None or playingref != ref:
1282                                 self.session.nav.playService(ref)
1283                                 config.radio.lastservice.value = ref.toString()
1284                                 config.radio.lastservice.save()
1285                         self.saveRoot()
1286
1287         def closeRadio(self):
1288                 self.info.hide()
1289                 #set previous tv service
1290                 lastservice=eServiceReference(config.tv.lastservice.value)
1291                 self.session.nav.playService(lastservice)
1292                 self.close(None)
1293
1294 class SimpleChannelSelection(ChannelSelectionBase):
1295         def __init__(self, session, title):
1296                 ChannelSelectionBase.__init__(self, session)
1297                 self.title = title
1298                 self.onShown.append(self.__onExecCallback)
1299
1300                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1301                         {
1302                                 "cancel": self.close,
1303                                 "ok": self.channelSelected,
1304                                 "keyRadio": self.setModeRadio,
1305                                 "keyTV": self.setModeTv,
1306                         })
1307
1308         def __onExecCallback(self):
1309                 self.setTitle(self.title)
1310                 self.setModeTv()
1311
1312         def channelSelected(self): # just return selected service
1313                 ref = self.getCurrentSelection()
1314                 if (ref.flags & 7) == 7:
1315                         self.enterPath(ref)
1316                 elif not (ref.flags & 64):
1317                         ref = self.getCurrentSelection()
1318                         self.close(ref)
1319
1320         def setModeTv(self):
1321                 self.setTvMode()
1322                 self.showFavourites()
1323
1324         def setModeRadio(self):
1325                 self.setRadioMode()
1326                 self.showFavourites()