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