reload bouquetlist when a new bouquet is added and the bouquet root is
[vuplus_dvbapp] / 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 = config.usage.multibouquet.value
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().toCompareString()) == -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 bouquets"), 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.toCompareString())
143                 self.close()
144
145         def removeParentalProtection(self, service):
146                 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"))
147
148         def pinEntered(self, service, result):
149                 if result:
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         def addServiceToBouquetSelected(self):
156                 bouquets = self.csel.getBouquetList()
157                 if bouquets is None:
158                         cnt = 0
159                 else:
160                         cnt = len(bouquets)
161                 if cnt > 1: # show bouquet list
162                         self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, bouquets, self.addCurrentServiceToBouquet)
163                 elif cnt == 1: # add to only one existing bouquet
164                         self.addCurrentServiceToBouquet(bouquets[0][1])
165
166         def bouquetSelClosed(self, recursive):
167                 self.bsel = None
168                 if recursive:
169                         self.close(False)
170
171         def copyCurrentToBouquetList(self):
172                 self.csel.copyCurrentToBouquetList()
173                 self.close()
174
175         def removeBouquet(self):
176                 self.csel.removeBouquet()
177                 self.close()
178
179         def showMarkerInputBox(self):
180                 self.session.openWithCallback(self.markerInputCallback, InputBox, title=_("Please enter a name for the new marker"), text="markername", maxSize=False, type=Input.TEXT)
181
182         def markerInputCallback(self, marker):
183                 if marker is not None:
184                         self.csel.addMarker(marker)
185                 self.close()
186
187         def addCurrentServiceToBouquet(self, dest):
188                 self.csel.addCurrentServiceToBouquet(dest)
189                 if self.bsel is not None:
190                         self.bsel.close(True)
191                 else:
192                         self.close(True) # close bouquet selection
193
194         def removeCurrentService(self):
195                 self.csel.removeCurrentService()
196                 self.close()
197
198         def toggleMoveMode(self):
199                 self.csel.toggleMoveMode()
200                 self.close()
201
202         def bouquetMarkStart(self):
203                 self.csel.startMarkedEdit()
204                 self.close()
205
206         def bouquetMarkEnd(self):
207                 self.csel.endMarkedEdit(abort=False)
208                 self.close()
209
210         def bouquetMarkAbort(self):
211                 self.csel.endMarkedEdit(abort=True)
212                 self.close()
213
214         def removeNewFoundFlag(self):
215                 eDVBDB.getInstance().removeFlag(self.csel.getCurrentSelection(), FLAG_SERVICE_NEW_FOUND)
216                 self.close()
217
218         def removeAllNewFoundFlags(self):
219                 curpath = self.csel.getCurrentSelection().getPath()
220                 idx = curpath.find("satellitePosition == ")
221                 if idx != -1:
222                         tmp = curpath[idx+21:]
223                         idx = tmp.find(')')
224                         if idx != -1:
225                                 satpos = int(tmp[:idx])
226                                 eDVBDB.getInstance().removeFlags(FLAG_SERVICE_NEW_FOUND, -1, -1, -1, satpos)
227                 self.close()
228
229 class ChannelSelectionEPG:
230         def __init__(self):
231                 self["ChannelSelectEPGActions"] = ActionMap(["ChannelSelectEPGActions"],
232                         {
233                                 "showEPGList": self.showEPGList,
234                         })
235
236         def showEPGList(self):
237                 ref=self.getCurrentSelection()
238                 ptr=eEPGCache.getInstance()
239                 if ptr.startTimeQuery(ref) != -1:
240                         self.session.open(EPGSelection, ref)
241                 else:
242                         print 'no epg for service', ref.toString()
243
244 class ChannelSelectionEdit:
245         def __init__(self):
246                 self.entry_marked = False
247                 self.movemode = False
248                 self.bouquet_mark_edit = False
249                 self.mutableList = None
250                 self.__marked = [ ]
251                 self.saved_title = None
252                 self.saved_root = None
253
254                 class ChannelSelectionEditActionMap(ActionMap):
255                         def __init__(self, csel, contexts = [ ], actions = { }, prio=0):
256                                 ActionMap.__init__(self, contexts, actions, prio)
257                                 self.csel = csel
258
259                         def action(self, contexts, action):
260                                 if action == "cancel":
261                                         self.csel.handleEditCancel()
262                                         return 0 # fall-trough
263                                 elif action == "ok":
264                                         return 0 # fall-trough
265                                 else:
266                                         return ActionMap.action(self, contexts, action)
267
268                 self["ChannelSelectEditActions"] = ChannelSelectionEditActionMap(self, ["ChannelSelectEditActions", "OkCancelActions"],
269                         {
270                                 "contextMenu": self.doContext,
271                         })
272
273         def getMutableList(self, root=eServiceReference()):
274                 if not self.mutableList is None:
275                         return self.mutableList
276                 serviceHandler = eServiceCenter.getInstance()
277                 if not root.valid():
278                         root=self.getRoot()
279                 list = root and serviceHandler.list(root)
280                 if list is not None:
281                         return list.startEdit()
282                 return None
283
284         def buildBouquetID(self, str):
285                 tmp = str.lower()
286                 name = ''
287                 for c in tmp:
288                         if (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9'):
289                                 name += c
290                         else:
291                                 name += '_'
292                 return name
293
294         def addMarker(self, name):
295                 current = self.servicelist.getCurrent()
296                 mutableList = self.getMutableList()
297                 cnt = 0
298                 while mutableList:
299                         str = '1:64:%d:0:0:0:0:0:0:0::%s'%(cnt, name)
300                         ref = eServiceReference(str)
301                         if current and current.valid():
302                                 if not mutableList.addService(ref, current):
303                                         self.servicelist.addService(ref, True)
304                                         mutableList.flushChanges()
305                                         break
306                         elif not mutableList.addService(ref):
307                                 self.servicelist.addService(ref, True)
308                                 mutableList.flushChanges()
309                                 break
310                         cnt+=1
311
312         def addBouquet(self, bName, services):
313                 serviceHandler = eServiceCenter.getInstance()
314                 mutableBouquetList = serviceHandler.list(self.bouquet_root).startEdit()
315                 if mutableBouquetList:
316                         if self.mode == MODE_TV:
317                                 bName += " (TV)"
318                                 str = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET \"userbouquet.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(bName))
319                         else:
320                                 bName += " (Radio)"
321                                 str = '1:7:2:0:0:0:0:0:0:0:(type == 2) FROM BOUQUET \"userbouquet.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(bName))
322                         new_bouquet_ref = eServiceReference(str)
323                         if not mutableBouquetList.addService(new_bouquet_ref):
324                                 self.bouquetNumOffsetCache = { }
325                                 mutableBouquetList.flushChanges()
326                                 eDVBDB.getInstance().reloadBouquets()
327                                 mutableBouquet = serviceHandler.list(new_bouquet_ref).startEdit()
328                                 if mutableBouquet:
329                                         mutableBouquet.setListName(bName)
330                                         if services is not None:
331                                                 for service in services:
332                                                         if mutableBouquet.addService(service):
333                                                                 print "add", service.toString(), "to new bouquet failed"
334                                                         else:
335                                                                 current = self.servicelist.getCurrent()
336                                                                 if current and current.toString() == self.bouquet_rootstr:
337                                                                         self.servicelist.addService(service, True)
338                                         mutableBouquet.flushChanges()
339                                 else:
340                                         print "get mutable list for new created bouquet failed"
341                                 # do some voodoo to check if current_root is equal to bouquet_root
342                                 cur_root = self.getRoot();
343                                 str1 = cur_root.toString()
344                                 pos1 = str1.find("FROM BOUQUET")
345                                 pos2 = self.bouquet_rootstr.find("FROM BOUQUET")
346                                 if pos1 != -1 and pos2 != -1 and str1[pos1:] == self.bouquet_rootstr[pos2:]:
347                                         self.setMode() #reload
348                         else:
349                                 print "add", str, "to bouquets failed"
350                 else:
351                         print "bouquetlist is not editable"
352
353         def copyCurrentToBouquetList(self):
354                 provider = ServiceReference(self.getCurrentSelection())
355                 providerName = provider.getServiceName()
356                 serviceHandler = eServiceCenter.getInstance()
357                 services = serviceHandler.list(provider.ref)
358                 self.addBouquet(providerName, services and services.getContent('R', True))
359
360         def removeBouquet(self):
361                 refstr = self.getCurrentSelection().toString()
362                 self.bouquetNumOffsetCache = { }
363                 pos = refstr.find('FROM BOUQUET "')
364                 if pos != -1:
365                         refstr = refstr[pos+14:]
366                         pos = refstr.find('"')
367                         if pos != -1:
368                                 filename = '/etc/enigma2/' + refstr[:pos] # FIXMEEE !!! HARDCODED /etc/enigma2
369                 self.removeCurrentService()
370                 try:
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 addCurrentServiceToBouquet(self, dest):
444                 mutableList = self.getMutableList(dest)
445                 if not mutableList is None:
446                         if not mutableList.addService(self.servicelist.getCurrent()):
447                                 self.bouquetNumOffsetCache = { }
448                                 mutableList.flushChanges()
449
450         def toggleMoveMode(self):
451                 if self.movemode:
452                         if self.entry_marked:
453                                 self.toggleMoveMarked() # unmark current entry
454                         self.movemode = False
455                         self.pathChangedDisabled = False # re-enable path change
456                         self.mutableList.flushChanges() # FIXME add check if changes was made
457                         self.mutableList = None
458                         self.setTitle(self.saved_title)
459                         self.saved_title = None
460                         if self.getRoot() == self.bouquet_root:
461                                 self.bouquetNumOffsetCache = { }
462                 else:
463                         self.mutableList = self.getMutableList()
464                         self.movemode = True
465                         self.pathChangedDisabled = True # no path change allowed in movemode
466                         self.saved_title = self.instance.getTitle()
467                         new_title = self.saved_title
468                         pos = self.saved_title.find(')')
469                         new_title = self.saved_title[:pos+1] + ' ' + _("[move mode]") + self.saved_title[pos+1:]
470                         self.setTitle(new_title);
471
472         def handleEditCancel(self):
473                 if self.movemode: #movemode active?
474                         self.channelSelected() # unmark
475                         self.toggleMoveMode() # disable move mode
476                 elif self.bouquet_mark_edit:
477                         self.endMarkedEdit(True) # abort edit mode
478
479         def toggleMoveMarked(self):
480                 if self.entry_marked:
481                         self.servicelist.setCurrentMarked(False)
482                         self.entry_marked = False
483                 else:
484                         self.servicelist.setCurrentMarked(True)
485                         self.entry_marked = True
486
487         def doContext(self):
488                 self.session.open(ChannelContextMenu, self)
489
490 MODE_TV = 0
491 MODE_RADIO = 1
492
493 # this makes it much simple to implement a selectable radio or tv mode :)
494 service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 195) || (type == 25)'
495 service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2)'
496
497 class ChannelSelectionBase(Screen):
498         def __init__(self, session):
499                 Screen.__init__(self, session)
500
501                 self["key_red"] = Button(_("All"))
502                 self["key_green"] = Button(_("Satellites"))
503                 self["key_yellow"] = Button(_("Provider"))
504                 self["key_blue"] = Button(_("Favourites"))
505
506                 self["list"] = ServiceList()
507                 self.servicelist = self["list"]
508
509                 self.numericalTextInput = NumericalTextInput()
510                 self.numericalTextInput.setUseableChars(u'1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ')
511
512                 self.servicePathTV = [ ]
513                 self.servicePathRadio = [ ]
514                 self.servicePath = [ ]
515
516                 self.mode = MODE_TV
517
518                 self.pathChangedDisabled = False
519
520                 self.bouquetNumOffsetCache = { }
521
522                 self["ChannelSelectBaseActions"] = NumberActionMap(["ChannelSelectBaseActions", "NumberActions"],
523                         {
524                                 "showFavourites": self.showFavourites,
525                                 "showAllServices": self.showAllServices,
526                                 "showProviders": self.showProviders,
527                                 "showSatellites": self.showSatellites,
528                                 "nextBouquet": self.nextBouquet,
529                                 "prevBouquet": self.prevBouquet,
530                                 "nextMarker": self.nextMarker,
531                                 "prevMarker": self.prevMarker,
532                                 "1": self.keyNumberGlobal,
533                                 "2": self.keyNumberGlobal,
534                                 "3": self.keyNumberGlobal,
535                                 "4": self.keyNumberGlobal,
536                                 "5": self.keyNumberGlobal,
537                                 "6": self.keyNumberGlobal,
538                                 "7": self.keyNumberGlobal,
539                                 "8": self.keyNumberGlobal,
540                                 "9": self.keyNumberGlobal,
541                                 "0": self.keyNumber0
542                         })
543                 self.recallBouquetMode()
544
545         def appendDVBTypes(self, ref):
546                 path = ref.getPath()
547                 pos = path.find(' FROM BOUQUET')
548                 if pos != -1:
549                         return eServiceReference(self.service_types + path[pos:])
550                 return ref
551
552         def getBouquetNumOffset(self, bouquet):
553                 if config.usage.multibouquet.value:
554                         return 0
555                 bouquet = self.appendDVBTypes(bouquet)
556                 try:
557                         return self.bouquetNumOffsetCache[bouquet.toString()]
558                 except:
559                         offsetCount = 0
560                         serviceHandler = eServiceCenter.getInstance()
561                         bouquetlist = serviceHandler.list(self.bouquet_root)
562                         if not bouquetlist is None:
563                                 while True:
564                                         bouquetIterator = self.appendDVBTypes(bouquetlist.getNext())
565                                         if not bouquetIterator.valid(): #end of list
566                                                 break
567                                         self.bouquetNumOffsetCache[bouquetIterator.toString()]=offsetCount
568                                         if ((bouquetIterator.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory):
569                                                 continue
570                                         servicelist = serviceHandler.list(bouquetIterator)
571                                         if not servicelist is None:
572                                                 while True:
573                                                         serviceIterator = servicelist.getNext()
574                                                         if not serviceIterator.valid(): #check if end of list
575                                                                 break
576                                                         if serviceIterator.flags: #playable services have no flags
577                                                                 continue
578                                                         offsetCount += 1
579                 return self.bouquetNumOffsetCache.get(bouquet.toString(), offsetCount)
580
581         def recallBouquetMode(self):
582                 if self.mode == MODE_TV:
583                         self.service_types = service_types_tv
584                         if config.usage.multibouquet.value:
585                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.tv" ORDER BY bouquet'
586                         else:
587                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)
588                 else:
589                         self.service_types = service_types_radio
590                         if config.usage.multibouquet.value:
591                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.radio" ORDER BY bouquet'
592                         else:
593                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(self.service_types)
594                 self.bouquet_root = eServiceReference(self.bouquet_rootstr)
595
596         def setTvMode(self):
597                 self.mode = MODE_TV
598                 self.servicePath = self.servicePathTV
599                 self.recallBouquetMode()
600                 title = self.instance.getTitle()
601                 pos = title.find(" (")
602                 if pos != -1:
603                         title = title[:pos]
604                 title += " (TV)"
605                 self.setTitle(title)
606
607         def setRadioMode(self):
608                 self.mode = MODE_RADIO
609                 self.servicePath = self.servicePathRadio
610                 self.recallBouquetMode()
611                 title = self.instance.getTitle()
612                 pos = title.find(" (")
613                 if pos != -1:
614                         title = title[:pos]
615                 title += " (Radio)"
616                 self.setTitle(title)
617
618         def setRoot(self, root, justSet=False):
619                 path = root.getPath()
620                 inBouquetRootList = path.find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
621                 pos = path.find(' FROM BOUQUET')
622                 isBouquet = pos != -1
623                 if not inBouquetRootList and isBouquet:
624                         self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
625                         self.servicelist.setNumberOffset(self.getBouquetNumOffset(root))
626                         refstr = self.service_types + path[pos:]
627                         root = eServiceReference(refstr)
628                 else:
629                         self.servicelist.setMode(ServiceList.MODE_NORMAL)
630                 self.servicelist.setRoot(root, justSet)
631                 self.buildTitleString()
632
633         def removeModeStr(self, str):
634                 if self.mode == MODE_TV:
635                         pos = str.find(' (TV)')
636                 else:
637                         pos = str.find(' (Radio)')
638                 if pos != -1:
639                         return str[:pos]
640                 return str
641
642         def getServiceName(self, ref):
643                 str = self.removeModeStr(ServiceReference(ref).getServiceName())
644                 if not len(str):
645                         pathstr = ref.getPath()
646                         if pathstr.find('FROM PROVIDERS') != -1:
647                                 return _("Provider")
648                         if pathstr.find('FROM SATELLITES') != -1:
649                                 return _("Satellites")
650                         if pathstr.find(') ORDER BY name') != -1:
651                                 return _("All")
652                 return str
653
654         def buildTitleString(self):
655                 titleStr = self.instance.getTitle()
656                 pos = titleStr.find(']')
657                 if pos == -1:
658                         pos = titleStr.find(')')
659                 if pos != -1:
660                         titleStr = titleStr[:pos+1]
661                         Len = len(self.servicePath)
662                         if Len > 0:
663                                 base_ref = self.servicePath[0]
664                                 if Len > 1:
665                                         end_ref = self.servicePath[Len-1]
666                                 else:
667                                         end_ref = None
668                                 nameStr = self.getServiceName(base_ref)
669                                 titleStr += ' ' + nameStr
670                                 if end_ref is not None:
671                                         if Len > 2:
672                                                 titleStr += '/../'
673                                         else:
674                                                 titleStr += '/'
675                                         nameStr = self.getServiceName(end_ref)
676                                         titleStr += nameStr
677                                 self.setTitle(titleStr)
678
679         def moveUp(self):
680                 self.servicelist.moveUp()
681
682         def moveDown(self):
683                 self.servicelist.moveDown()
684
685         def clearPath(self):
686                 del self.servicePath[:]
687
688         def enterPath(self, ref, justSet=False):
689                 self.servicePath.append(ref)
690                 self.setRoot(ref, justSet)
691
692         def pathUp(self, justSet=False):
693                 prev = self.servicePath.pop()
694                 length = len(self.servicePath)
695                 if length:
696                         current = self.servicePath[length-1]
697                         self.setRoot(current, justSet)
698                         if not justSet:
699                                 self.setCurrentSelection(prev)
700                 return prev
701
702         def isBasePathEqual(self, ref):
703                 if len(self.servicePath) > 1 and self.servicePath[0] == ref:
704                         return True
705                 return False
706
707         def isPrevPathEqual(self, ref):
708                 length = len(self.servicePath)
709                 if length > 1 and self.servicePath[length-2] == ref:
710                         return True
711                 return False
712
713         def preEnterPath(self, refstr):
714                 return False
715
716         def showAllServices(self):
717                 if not self.pathChangedDisabled:
718                         refstr = '%s ORDER BY name'%(self.service_types)
719                         if not self.preEnterPath(refstr):
720                                 ref = eServiceReference(refstr)
721                                 currentRoot = self.getRoot()
722                                 if currentRoot is None or currentRoot != ref:
723                                         self.clearPath()
724                                         self.enterPath(ref)
725
726         def showSatellites(self):
727                 if not self.pathChangedDisabled:
728                         refstr = '%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)
729                         if not self.preEnterPath(refstr):
730                                 ref = eServiceReference(refstr)
731                                 justSet=False
732                                 prev = None
733
734                                 if self.isBasePathEqual(ref):
735                                         if self.isPrevPathEqual(ref):
736                                                 justSet=True
737                                         prev = self.pathUp(justSet)
738                                 else:
739                                         currentRoot = self.getRoot()
740                                         if currentRoot is None or currentRoot != ref:
741                                                 justSet=True
742                                                 self.clearPath()
743                                                 self.enterPath(ref, True)
744                                 if justSet:
745                                         serviceHandler = eServiceCenter.getInstance()
746                                         servicelist = serviceHandler.list(ref)
747                                         if not servicelist is None:
748                                                 while True:
749                                                         service = servicelist.getNext()
750                                                         if not service.valid(): #check if end of list
751                                                                 break
752                                                         orbpos = service.getUnsignedData(4) >> 16
753                                                         if service.getPath().find("FROM PROVIDER") != -1:
754                                                                 service_name = _("Providers")
755                                                         elif service.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
756                                                                 service_name = _("New")
757                                                         else:
758                                                                 service_name = _("Services")
759                                                         try:
760                                                                 service_name += str(' - %s'%(nimmanager.getSatDescription(orbpos)))
761                                                                 service.setName(service_name) # why we need this cast?
762                                                         except:
763                                                                 if orbpos == 0xFFFF: #Cable
764                                                                         n = ("%s (%s)") % (service_name, _("Cable"))
765                                                                 elif orbpos == 0xEEEE: #Terrestrial
766                                                                         n = ("%s (%s)") % (service_name, _("Terrestrial"))
767                                                                 else:
768                                                                         if orbpos > 1800: # west
769                                                                                 orbpos = 3600 - orbpos
770                                                                                 h = _("W")
771                                                                         else:
772                                                                                 h = _("E")
773                                                                         n = ("%s (%d.%d" + h + ")") % (service_name, orbpos / 10, orbpos % 10)
774                                                                 service.setName(n)
775                                                         self.servicelist.addService(service)
776                                                 self.servicelist.finishFill()
777                                                 if prev is not None:
778                                                         self.setCurrentSelection(prev)
779
780         def showProviders(self):
781                 if not self.pathChangedDisabled:
782                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
783                         if not self.preEnterPath(refstr):
784                                 ref = eServiceReference(refstr)
785                                 if self.isBasePathEqual(ref):
786                                         self.pathUp()
787                                 else:
788                                         currentRoot = self.getRoot()
789                                         if currentRoot is None or currentRoot != ref:
790                                                 self.clearPath()
791                                                 self.enterPath(ref)
792
793         def changeBouquet(self, direction):
794                 if not self.pathChangedDisabled:
795                         if self.isBasePathEqual(self.bouquet_root):
796                                 self.pathUp()
797                                 if direction < 0:
798                                         self.moveUp()
799                                 else:
800                                         self.moveDown()
801                                 ref = self.getCurrentSelection()
802                                 self.enterPath(ref)
803
804         def inBouquet(self):
805                 return self.isBasePathEqual(self.bouquet_root)
806
807         def atBegin(self):
808                 return self.servicelist.atBegin()
809
810         def atEnd(self):
811                 return self.servicelist.atEnd()
812
813         def nextBouquet(self):
814                 self.changeBouquet(+1)
815
816         def prevBouquet(self):
817                 self.changeBouquet(-1)
818
819         def showFavourites(self):
820                 if not self.pathChangedDisabled:
821                         if not self.preEnterPath(self.bouquet_rootstr):
822                                 if self.isBasePathEqual(self.bouquet_root):
823                                         self.pathUp()
824                                 else:
825                                         currentRoot = self.getRoot()
826                                         if currentRoot is None or currentRoot != self.bouquet_root:
827                                                 self.clearPath()
828                                                 self.enterPath(self.bouquet_root)
829
830         def keyNumberGlobal(self, number):
831                 unichar = self.numericalTextInput.getKey(number)
832                 charstr = unichar.encode("utf-8")
833                 if len(charstr) == 1:
834                         self.servicelist.moveToChar(charstr[0])
835
836         def getRoot(self):
837                 return self.servicelist.getRoot()
838
839         def getCurrentSelection(self):
840                 return self.servicelist.getCurrent()
841
842         def setCurrentSelection(self, service):
843                 servicepath = service.getPath()
844                 pos = servicepath.find(" FROM BOUQUET")
845                 if pos != -1:
846                         if self.mode == MODE_TV:
847                                 servicepath = '(type == 1)' + servicepath[pos:]
848                         else:
849                                 servicepath = '(type == 2)' + servicepath[pos:]
850                         service.setPath(servicepath)
851                 self.servicelist.setCurrent(service)
852
853         def getBouquetList(self):
854                 bouquets = [ ]
855                 serviceHandler = eServiceCenter.getInstance()
856                 if config.usage.multibouquet.value:
857                         list = serviceHandler.list(self.bouquet_root)
858                         if not list is None:
859                                 while True:
860                                         s = list.getNext()
861                                         if not s.valid():
862                                                 break
863                                         if ((s.flags & eServiceReference.flagDirectory) == eServiceReference.flagDirectory):
864                                                 info = serviceHandler.info(s)
865                                                 if not info is None:
866                                                         bouquets.append((info.getName(s), s))
867                                 return bouquets
868                 else:
869                         info = serviceHandler.info(self.bouquet_root)
870                         if not info is None:
871                                 bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
872                         return bouquets
873                 return None
874
875         def keyNumber0(self, num):
876                 if len(self.servicePath) > 1:
877                         self.keyGoUp()
878                 else:
879                         self.keyNumberGlobal(num)
880
881         def keyGoUp(self):
882                 if len(self.servicePath) > 1:
883                         if self.isBasePathEqual(self.bouquet_root):
884                                 self.showFavourites()
885                         else:
886                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
887                                 if self.isBasePathEqual(ref):
888                                         self.showSatellites()
889                                 else:
890                                         ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
891                                         if self.isBasePathEqual(ref):
892                                                 self.showProviders()
893                                         else:
894                                                 self.showAllServices()
895
896         def nextMarker(self):
897                 self.servicelist.moveToNextMarker()
898
899         def prevMarker(self):
900                 self.servicelist.moveToPrevMarker()
901
902 HISTORYSIZE = 20
903
904 #config for lastservice
905 config.tv = ConfigSubsection()
906 config.tv.lastservice = ConfigText()
907 config.tv.lastroot = ConfigText()
908 config.radio = ConfigSubsection()
909 config.radio.lastservice = ConfigText()
910 config.radio.lastroot = ConfigText()
911 config.servicelist = ConfigSubsection()
912 config.servicelist.lastmode = ConfigText(default = "tv")
913
914 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
915         def __init__(self, session):
916                 ChannelSelectionBase.__init__(self,session)
917                 ChannelSelectionEdit.__init__(self)
918                 ChannelSelectionEPG.__init__(self)
919
920                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
921                         {
922                                 "cancel": self.cancel,
923                                 "ok": self.channelSelected,
924                                 "keyRadio": self.setModeRadio,
925                                 "keyTV": self.setModeTv,
926                         })
927
928                 self.onShown.append(self.__onShown)
929
930                 self.lastChannelRootTimer = eTimer()
931                 self.lastChannelRootTimer.timeout.get().append(self.__onCreate)
932                 self.lastChannelRootTimer.start(100,True)
933
934                 self.history_tv = [ ]
935                 self.history_radio = [ ]
936                 self.history = self.history_tv
937                 self.history_pos = 0
938
939                 self.lastservice = config.tv.lastservice
940                 self.lastroot = config.tv.lastroot
941                 self.revertMode = None
942
943         def setMode(self):
944                 self.restoreRoot()
945                 lastservice=eServiceReference(self.lastservice.value)
946                 if lastservice.valid():
947                         self.setCurrentSelection(lastservice)
948
949         def setModeTv(self):
950                 if self.revertMode is None and config.servicelist.lastmode.value == "radio":
951                         self.revertMode = MODE_RADIO
952                 self.history = self.history_tv
953                 self.lastservice = config.tv.lastservice
954                 self.lastroot = config.tv.lastroot
955                 config.servicelist.lastmode.value = "tv"
956                 self.setTvMode()
957                 self.setMode()
958
959         def setModeRadio(self):
960                 if self.revertMode is None and config.servicelist.lastmode.value == "tv":
961                         self.revertMode = MODE_TV
962                 if config.usage.e1like_radio_mode.value:
963                         self.history = self.history_radio
964                         self.lastservice = config.radio.lastservice
965                         self.lastroot = config.radio.lastroot
966                         config.servicelist.lastmode.value = "radio"
967                         self.setRadioMode()
968                         self.setMode()
969
970         def __onCreate(self):
971                 if config.usage.e1like_radio_mode.value:
972                         if config.servicelist.lastmode.value == "tv":
973                                 self.setModeTv()
974                         else:
975                                 self.setModeRadio()
976                 else:
977                         self.setModeTv()
978                 lastservice=eServiceReference(self.lastservice.value)
979                 if lastservice.valid():
980                         self.zap()
981
982         def __onShown(self):
983                 self.recallBouquetMode()
984                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
985                 if ref is not None and ref.valid() and ref.getPath() == "":
986                         self.servicelist.setPlayableIgnoreService(ref)
987                 else:
988                         self.servicelist.setPlayableIgnoreService(eServiceReference())
989
990         def channelSelected(self):
991                 ref = self.getCurrentSelection()
992                 if self.movemode:
993                         self.toggleMoveMarked()
994                 elif (ref.flags & 7) == 7:
995                         self.enterPath(ref)
996                 elif self.bouquet_mark_edit:
997                         self.doMark()
998                 elif not (ref.flags & 64): # no marker
999                         self.zap()
1000                         self.close(ref)
1001
1002         #called from infoBar and channelSelected
1003         def zap(self):
1004                 self.revertMode=None
1005                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1006                 nref = self.getCurrentSelection()
1007                 if ref is None or ref != nref:
1008                         self.session.nav.playService(nref)
1009                         self.saveRoot()
1010                         self.saveChannel()
1011                         config.servicelist.lastmode.save()
1012                         self.addToHistory(nref)
1013
1014         def addToHistory(self, ref):
1015                 if self.servicePath is not None:
1016                         tmp=self.servicePath[:]
1017                         tmp.append(ref)
1018                         try:
1019                                 del self.history[self.history_pos+1:]
1020                         except:
1021                                 pass
1022                         self.history.append(tmp)
1023                         hlen = len(self.history)
1024                         if hlen > HISTORYSIZE:
1025                                 del self.history[0]
1026                                 hlen -= 1
1027                         self.history_pos = hlen-1
1028
1029         def historyBack(self):
1030                 hlen = len(self.history)
1031                 if hlen > 1 and self.history_pos > 0:
1032                         self.history_pos -= 1
1033                         self.setHistoryPath()
1034
1035         def historyNext(self):
1036                 hlen = len(self.history)
1037                 if hlen > 1 and self.history_pos < (hlen-1):
1038                         self.history_pos += 1
1039                         self.setHistoryPath()
1040
1041         def setHistoryPath(self):
1042                 path = self.history[self.history_pos][:]
1043                 ref = path.pop()
1044                 del self.servicePath[:]
1045                 self.servicePath += path
1046                 self.saveRoot()
1047                 plen = len(path)
1048                 root = path[plen-1]
1049                 if self.getRoot() != root:
1050                         self.setRoot(root)
1051                 self.session.nav.playService(ref)
1052                 self.setCurrentSelection(ref)
1053                 self.saveChannel()
1054
1055         def saveRoot(self):
1056                 path = ''
1057                 for i in self.servicePath:
1058                         path += i.toString()
1059                         path += ';'
1060                 if len(path) and path != self.lastroot.value:
1061                         self.lastroot.value = path
1062                         self.lastroot.save()
1063
1064         def restoreRoot(self):
1065                 self.clearPath()
1066                 re = compile('.+?;')
1067                 tmp = re.findall(self.lastroot.value)
1068                 cnt = 0
1069                 for i in tmp:
1070                         self.servicePath.append(eServiceReference(i[:len(i)-1]))
1071                         cnt += 1
1072                 if cnt:
1073                         path = self.servicePath.pop()
1074                         self.enterPath(path)
1075                 else:
1076                         self.showFavourites()
1077                         self.saveRoot()
1078
1079         def preEnterPath(self, refstr):
1080                 if len(self.servicePath) and self.servicePath[0] != eServiceReference(refstr):
1081                         pathstr = self.lastroot.value
1082                         if pathstr is not None and pathstr.find(refstr) == 0:
1083                                 self.restoreRoot()
1084                                 lastservice=eServiceReference(self.lastservice.value)
1085                                 if lastservice.valid():
1086                                         self.setCurrentSelection(lastservice)
1087                                 return True
1088                 return False
1089
1090         def saveChannel(self):
1091                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1092                 if ref is not None:
1093                         refstr = ref.toString()
1094                 else:
1095                         refstr = ""
1096                 if refstr != self.lastservice.value:
1097                         self.lastservice.value = refstr
1098                         self.lastservice.save()
1099
1100         def setCurrentServicePath(self, path):
1101                 hlen = len(self.history)
1102                 if hlen > 0:
1103                         self.history[self.history_pos] = path
1104                 else:
1105                         self.history.append(path)
1106                 self.setHistoryPath()
1107
1108         def getCurrentServicePath(self):
1109                 hlen = len(self.history)
1110                 if hlen > 0:
1111                         return self.history[self.history_pos]
1112                 return None
1113
1114         def recallPrevService(self):
1115                 hlen = len(self.history)
1116                 if hlen > 1:
1117                         if self.history_pos == hlen-1:
1118                                 tmp = self.history[self.history_pos]
1119                                 self.history[self.history_pos] = self.history[self.history_pos-1]
1120                                 self.history[self.history_pos-1] = tmp
1121                         else:
1122                                 tmp = self.history[self.history_pos+1]
1123                                 self.history[self.history_pos+1] = self.history[self.history_pos]
1124                                 self.history[self.history_pos] = tmp
1125                         self.setHistoryPath()
1126
1127         def cancel(self):
1128                 if self.revertMode is None:
1129                         self.restoreRoot()
1130                         lastservice=eServiceReference(self.lastservice.value)
1131                         if lastservice.valid() and self.getCurrentSelection() != lastservice:
1132                                 self.setCurrentSelection(lastservice)
1133                 elif self.revertMode == MODE_TV:
1134                         self.setModeTv()
1135                 elif self.revertMode == MODE_RADIO:
1136                         self.setModeRadio()
1137                 self.revertMode = None
1138                 self.close(None)
1139
1140 from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord, InfoBarRadioText
1141
1142 class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord):
1143         def __init__(self, session):
1144                 Screen.__init__(self, session)
1145                 InfoBarEvent.__init__(self)
1146                 InfoBarServiceName.__init__(self)
1147                 InfoBarInstantRecord.__init__(self)
1148                 self["CurrentTime"] = Clock()
1149
1150 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, InfoBarRadioText):
1151
1152         ALLOW_SUSPEND = True
1153
1154         def __init__(self, session):
1155                 ChannelSelectionBase.__init__(self, session)
1156                 ChannelSelectionEdit.__init__(self)
1157                 ChannelSelectionEPG.__init__(self)
1158                 InfoBarRadioText.__init__(self)
1159
1160                 config.radio = ConfigSubsection();
1161                 config.radio.lastservice = ConfigText()
1162                 config.radio.lastroot = ConfigText()
1163                 self.onLayoutFinish.append(self.onCreate)
1164
1165                 self.info = session.instantiateDialog(RadioInfoBar)
1166
1167                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1168                         {
1169                                 "keyTV": self.closeRadio,
1170                                 "keyRadio": self.closeRadio,
1171                                 "cancel": self.closeRadio,
1172                                 "ok": self.channelSelected,
1173                         })
1174
1175         def saveRoot(self):
1176                 path = ''
1177                 for i in self.servicePathRadio:
1178                         path += i.toString()
1179                         path += ';'
1180                 if len(path) and path != config.radio.lastroot.value:
1181                         config.radio.lastroot.value = path
1182                         config.radio.lastroot.save()
1183
1184         def restoreRoot(self):
1185                 self.clearPath()
1186                 re = compile('.+?;')
1187                 tmp = re.findall(config.radio.lastroot.value)
1188                 cnt = 0
1189                 for i in tmp:
1190                         self.servicePathRadio.append(eServiceReference(i[:len(i)-1]))
1191                         cnt += 1
1192                 if cnt:
1193                         path = self.servicePathRadio.pop()
1194                         self.enterPath(path)
1195                 else:
1196                         self.showFavourites()
1197                         self.saveRoot()
1198
1199         def preEnterPath(self, refstr):
1200                 if len(self.servicePathRadio) and self.servicePathRadio[0] != eServiceReference(refstr):
1201                         pathstr = config.radio.lastroot.value
1202                         if pathstr is not None and pathstr.find(refstr) == 0:
1203                                 self.restoreRoot()
1204                                 lastservice=eServiceReference(config.radio.lastservice.value)
1205                                 if lastservice.valid():
1206                                         self.setCurrentSelection(lastservice)
1207                                 return True
1208                 return False
1209
1210         def onCreate(self):
1211                 self.setRadioMode()
1212                 self.restoreRoot()
1213                 lastservice=eServiceReference(config.radio.lastservice.value)
1214                 if lastservice.valid():
1215                         self.servicelist.setCurrent(lastservice)
1216                         self.session.nav.playService(lastservice)
1217                         self.servicelist.setPlayableIgnoreService(lastservice)
1218                 self.info.show()
1219
1220         def channelSelected(self): # just return selected service
1221                 ref = self.getCurrentSelection()
1222                 if self.movemode:
1223                         self.toggleMoveMarked()
1224                 elif (ref.flags & 7) == 7:
1225                         self.enterPath(ref)
1226                 elif self.bouquet_mark_edit:
1227                         self.doMark()
1228                 elif not (ref.flags & 64): # no marker
1229                         playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1230                         if playingref is None or playingref != ref:
1231                                 self.session.nav.playService(ref)
1232                                 self.servicelist.setPlayableIgnoreService(ref)
1233                                 config.radio.lastservice.value = ref.toString()
1234                                 config.radio.lastservice.save()
1235                         self.saveRoot()
1236
1237         def closeRadio(self):
1238                 self.info.hide()
1239                 #set previous tv service
1240                 lastservice=eServiceReference(config.tv.lastservice.value)
1241                 self.session.nav.playService(lastservice)
1242                 self.close(None)
1243
1244 class SimpleChannelSelection(ChannelSelectionBase):
1245         def __init__(self, session, title):
1246                 ChannelSelectionBase.__init__(self, session)
1247                 self.title = title
1248                 self.onShown.append(self.__onExecCallback)
1249
1250                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1251                         {
1252                                 "cancel": self.close,
1253                                 "ok": self.channelSelected,
1254                                 "keyRadio": self.setModeRadio,
1255                                 "keyTV": self.setModeTv,
1256                         })
1257
1258         def __onExecCallback(self):
1259                 self.setTitle(self.title)
1260                 self.setModeTv()
1261
1262         def channelSelected(self): # just return selected service
1263                 ref = self.getCurrentSelection()
1264                 if (ref.flags & 7) == 7:
1265                         self.enterPath(ref)
1266                 elif not (ref.flags & 64):
1267                         ref = self.getCurrentSelection()
1268                         self.close(ref)
1269
1270         def setModeTv(self):
1271                 self.setTvMode()
1272                 self.showFavourites()
1273
1274         def setModeRadio(self):
1275                 self.setRadioMode()
1276                 self.showFavourites()