4.3.2r12
[enigma2.git] / usr / lib / enigma2 / python / Screens / ChannelSelection.py
1 from Tools.Profile import profile
2
3 from Screen import Screen
4 from Components.Button import Button
5 from Components.ServiceList import ServiceList
6 from Components.ActionMap import NumberActionMap, ActionMap, HelpableActionMap
7 from Components.MenuList import MenuList
8 from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
9 from Screens.ChoiceBox import ChoiceBox
10 profile("ChannelSelection.py 1")
11 from EpgSelection import EPGSelection
12 from enigma import eServiceReference, eServiceCenter, eTimer, eDVBDB, iPlayableService, iServiceInformation, getPrevAsciiCode, eEnv, eEPGCache
13 from Components.config import config, ConfigSubsection, ConfigText, NoSave, ConfigBoolean
14 from Tools.NumericalTextInput import NumericalTextInput
15 profile("ChannelSelection.py 2")
16 from Components.NimManager import nimmanager
17 profile("ChannelSelection.py 2.1")
18 from Components.Sources.RdsDecoder import RdsDecoder
19 profile("ChannelSelection.py 2.2")
20 from Components.Sources.ServiceEvent import ServiceEvent
21 profile("ChannelSelection.py 2.3")
22 from Components.Input import Input
23 profile("ChannelSelection.py 3")
24 from Components.ChoiceList import ChoiceList, ChoiceEntryComponent
25 from Components.SystemInfo import SystemInfo
26 from Screens.InputBox import InputBox, PinInput
27 from Screens.MessageBox import MessageBox
28 from Screens.ServiceInfo import ServiceInfo
29 profile("ChannelSelection.py 4")
30 from Screens.PictureInPicture import PictureInPicture
31 import Screens.Standby
32 from ServiceReference import ServiceReference
33 from Tools.BoundFunction import boundFunction
34 from os import remove
35 from Plugins.Plugin import PluginDescriptor
36 from Components.PluginComponent import plugins
37 from ChannelSelectionDisplaySettings import ChannelSelectionDisplaySettings
38 profile("ChannelSelection.py after imports")
39
40 FLAG_SERVICE_NEW_FOUND = 64 #define in lib/dvb/idvb.h as dxNewFound = 64
41
42 class BouquetSelector(Screen):
43         def __init__(self, session, bouquets, selectedFunc, enableWrapAround=False):
44                 Screen.__init__(self, session)
45
46                 self.selectedFunc=selectedFunc
47
48                 self["actions"] = ActionMap(["OkCancelActions"],
49                         {
50                                 "ok": self.okbuttonClick,
51                                 "cancel": self.cancelClick
52                         })
53                 entrys = [ (x[0], x[1]) for x in bouquets ]
54                 self["menu"] = MenuList(entrys, enableWrapAround)
55
56         def getCurrent(self):
57                 cur = self["menu"].getCurrent()
58                 return cur and cur[1]
59
60         def okbuttonClick(self):
61                 self.selectedFunc(self.getCurrent())
62
63         def up(self):
64                 self["menu"].up()
65
66         def down(self):
67                 self["menu"].down()
68
69         def cancelClick(self):
70                 self.close(False)
71
72 class SilentBouquetSelector:
73         def __init__(self, bouquets, enableWrapAround=False, current=0):
74                 self.bouquets = [b[1] for b in bouquets]
75                 self.pos = current
76                 self.count = len(bouquets)
77                 self.enableWrapAround = enableWrapAround
78
79         def up(self):
80                 if self.pos > 0 or self.enableWrapAround:
81                         self.pos = (self.pos - 1) % self.count
82
83         def down(self):
84                 if self.pos < (self.count - 1) or self.enableWrapAround:
85                         self.pos = (self.pos + 1) % self.count
86
87         def getCurrent(self):
88                 return self.bouquets[self.pos]
89
90 # csel.bouquet_mark_edit values
91 OFF = 0
92 EDIT_BOUQUET = 1
93 EDIT_ALTERNATIVES = 2
94
95 def append_when_current_valid(current, menu, args, level = 0, key = ""):
96         if current and current.valid() and level <= config.usage.setup_level.index:
97                 menu.append(ChoiceEntryComponent(key, args))
98
99 def append_when_level(menu, args, level = 0, key = ""):
100         if level <= config.usage.setup_level.index:
101                 menu.append(ChoiceEntryComponent(key, args))
102
103 class ChannelContextMenu(Screen):
104         ALLOW_SUSPEND = True
105
106         def __init__(self, session, csel):
107
108                 Screen.__init__(self, session)
109                 #raise Exception("we need a better summary screen here")
110                 self.csel = csel
111                 self.bsel = None
112
113                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions"],
114                         {
115                                 "ok": self.okbuttonClick,
116                                 "cancel": self.cancelClick,
117                                 "blue": self.showServiceInPiP
118                         })
119                 menu = [ ]
120
121                 self.pipAvailable = False
122                 current = csel.getCurrentSelection()
123                 current_root = csel.getRoot()
124                 current_root_path = current_root and current_root.getPath()
125                 current_sel_path = current.getPath()
126                 current_sel_flags = current.flags
127
128                 inBouquetRootList = current_root_path and current_root_path.find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
129                 inBouquet = csel.getMutableList() is not None
130                 haveBouquets = config.usage.multibouquet.value
131                 channel_context_menu_plugins = plugins.getPlugins(PluginDescriptor.WHERE_CHANNEL_CONTEXT_MENU)
132
133                 isPlayableService = not (current_sel_path or current_sel_flags & (eServiceReference.isDirectory|eServiceReference.isMarker))
134                 if isPlayableService:
135                         append_when_current_valid(current, menu, (_("show transponder info"), self.showServiceInformations), level = 2)
136
137                 plugins_to_remove = []
138                 for p in channel_context_menu_plugins:
139                         if p.helperfnc != None:
140                                 if p.helperfnc(csel):
141                                         append_when_level(menu, (p.description, boundFunction(self.execPlugin, p, csel.getCurrentSelection())))
142                                 plugins_to_remove.append(p)
143                 channel_context_menu_plugins = [x for x in channel_context_menu_plugins if x not in plugins_to_remove]
144                 plugins_to_remove = None
145
146                 if isPlayableService:
147                         for p in channel_context_menu_plugins:
148                                 append_when_current_valid(current, menu, (p.description, boundFunction(self.execPlugin, p, csel.getCurrentSelection())))
149                 if csel.bouquet_mark_edit == OFF and not csel.movemode:
150                         if not inBouquetRootList:
151                                 isPlayable = not (current_sel_flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
152                                 if isPlayable:
153                                         if config.ParentalControl.configured.value:
154                                                 from Components.ParentalControl import parentalControl
155                                                 if parentalControl.getProtectionLevel(csel.getCurrentSelection().toCompareString()) == -1:
156                                                         append_when_current_valid(current, menu, (_("add to parental protection"), boundFunction(self.addParentalProtection, csel.getCurrentSelection())), level = 0)
157                                                 else:
158                                                         append_when_current_valid(current, menu, (_("remove from parental protection"), boundFunction(self.removeParentalProtection, csel.getCurrentSelection())), level = 0)
159                                         if haveBouquets:
160                                                 bouquets = self.csel.getBouquetList()
161                                                 if bouquets is None:
162                                                         bouquetCnt = 0
163                                                 else:
164                                                         bouquetCnt = len(bouquets)
165                                                 if not inBouquet or bouquetCnt > 1:
166                                                         append_when_current_valid(current, menu, (_("add service to bouquet"), self.addServiceToBouquetSelected), level = 0)
167                                         else:
168                                                 if not inBouquet:
169                                                         append_when_current_valid(current, menu, (_("add service to favourites"), self.addServiceToBouquetSelected), level = 0)
170                                 else:
171                                         if current_root_path.find('FROM SATELLITES') != -1:
172                                                 unsigned_orbpos = current.getUnsignedData(4) >> 16
173                                                 print "unsigned orbpos %08x" %unsigned_orbpos
174                                                 if unsigned_orbpos == 0xFFFF: #Cable
175                                                         append_when_current_valid(current, menu, (_("remove cable services"), self.removeSatelliteServices), level = 0)
176                                                 elif unsigned_orbpos == 0xEEEE: #Terrestrial
177                                                         append_when_current_valid(current, menu, (_("remove terrestrial services"), self.removeSatelliteServices), level = 0)
178                                                 else:
179                                                         append_when_current_valid(current, menu, (_("remove selected satellite"), self.removeSatelliteServices), level = 0)
180                                         if haveBouquets:
181                                                 if not inBouquet and current_sel_path.find("PROVIDERS") == -1:
182                                                         append_when_current_valid(current, menu, (_("copy to bouquets"), self.copyCurrentToBouquetList), level = 0)
183                                         if current_sel_path.find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
184                                                 append_when_current_valid(current, menu, (_("remove all new found flags"), self.removeAllNewFoundFlags), level = 0)
185                                 if inBouquet:
186                                         append_when_current_valid(current, menu, (_("remove entry"), self.removeCurrentService), level = 0)
187                                         append_when_current_valid(current, menu, (_("rename entry"), self.renameSelectedEntry), level = 0)
188                                 if current_root and current_root.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
189                                         append_when_current_valid(current, menu, (_("remove new found flag"), self.removeNewFoundFlag), level = 0)
190                                 if isPlayable and SystemInfo.get("NumVideoDecoders", 1) > 1 and not isinstance(self.csel, ChannelSelectionRadio):
191                                         append_when_current_valid(current, menu, (_("Activate Picture in Picture"), self.showServiceInPiP), level = 0, key = "blue")
192                                         self.pipAvailable = True
193                         else:
194                                         menu.append(ChoiceEntryComponent(text = (_("add bouquet"), self.showBouquetInputBox)))
195                                         append_when_current_valid(current, menu, (_("remove entry"), self.removeBouquet), level = 0)
196                                         append_when_current_valid(current, menu, (_("rename entry"), self.renameSelectedEntry), level = 0)
197
198                 if inBouquet: # current list is editable?
199                         if csel.bouquet_mark_edit == OFF:
200                                 if not csel.movemode:
201                                         append_when_current_valid(current, menu, (_("enable move mode"), self.toggleMoveMode), level = 1)
202                                         if not inBouquetRootList and current_root and not (current_root.flags & eServiceReference.isGroup):
203                                                 menu.append(ChoiceEntryComponent(text = (_("add marker"), self.showMarkerInputBox)))
204                                                 if haveBouquets:
205                                                         append_when_current_valid(current, menu, (_("enable bouquet edit"), self.bouquetMarkStart), level = 0)
206                                                 else:
207                                                         append_when_current_valid(current, menu, (_("enable favourite edit"), self.bouquetMarkStart), level = 0)
208                                                 if current_sel_flags & eServiceReference.isGroup:
209                                                         append_when_current_valid(current, menu, (_("edit alternatives"), self.editAlternativeServices), level = 2)
210                                                         append_when_current_valid(current, menu, (_("show alternatives"), self.showAlternativeServices), level = 2)
211                                                         append_when_current_valid(current, menu, (_("remove all alternatives"), self.removeAlternativeServices), level = 2)
212                                                 elif not current_sel_flags & eServiceReference.isMarker:
213                                                         append_when_current_valid(current, menu, (_("add alternatives"), self.addAlternativeServices), level = 2)
214                                 else:
215                                         append_when_current_valid(current, menu, (_("disable move mode"), self.toggleMoveMode), level = 0)
216                         else:
217                                 if csel.bouquet_mark_edit == EDIT_BOUQUET:
218                                         if haveBouquets:
219                                                 append_when_current_valid(current, menu, (_("end bouquet edit"), self.bouquetMarkEnd), level = 0)
220                                                 append_when_current_valid(current, menu, (_("abort bouquet edit"), self.bouquetMarkAbort), level = 0)
221                                         else:
222                                                 append_when_current_valid(current, menu, (_("end favourites edit"), self.bouquetMarkEnd), level = 0)
223                                                 append_when_current_valid(current, menu, (_("abort favourites edit"), self.bouquetMarkAbort), level = 0)
224                                 else:
225                                                 append_when_current_valid(current, menu, (_("end alternatives edit"), self.bouquetMarkEnd), level = 0)
226                                                 append_when_current_valid(current, menu, (_("abort alternatives edit"), self.bouquetMarkAbort), level = 0)
227
228                 append_when_current_valid(current, menu, (_("ChannelSelection Display Settings"), self.displaySettings), level = 2)
229
230                 menu.append(ChoiceEntryComponent(text = (_("back"), self.cancelClick)))
231                 self["menu"] = ChoiceList(menu)
232
233         def okbuttonClick(self):
234                 self["menu"].getCurrent()[0][1]()
235
236         def cancelClick(self):
237                 self.close(False)
238
239         def displaySettings(self):
240                 self.session.openWithCallback(self.close, ChannelSelectionDisplaySettings)
241
242         def showServiceInformations(self):
243                 self.session.open( ServiceInfo, self.csel.getCurrentSelection() )
244
245         def showBouquetInputBox(self):
246                 self.session.openWithCallback(self.bouquetInputCallback, InputBox, title=_("Please enter a name for the new bouquet"), text="bouquetname", maxSize=False, visible_width = 56, type=Input.TEXT)
247
248         def bouquetInputCallback(self, bouquet):
249                 if bouquet is not None:
250                         self.csel.addBouquet(bouquet, None)
251                 self.close()
252
253         def addParentalProtection(self, service):
254                 from Components.ParentalControl import parentalControl
255                 parentalControl.protectService(service.toCompareString())
256                 self.close()
257
258         def removeParentalProtection(self, service):
259                 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"))
260
261         def pinEntered(self, service, result):
262                 if result:
263                         from Components.ParentalControl import parentalControl
264                         parentalControl.unProtectService(service)
265                         self.close()
266                 else:
267                         self.session.openWithCallback(self.close, MessageBox, _("The pin code you entered is wrong."), MessageBox.TYPE_ERROR)
268
269         def showServiceInPiP(self):
270                 if not self.pipAvailable:
271                         return
272                 if self.session.pipshown:
273                         self.session.deleteDialog(self.session.pip)
274                         del self.session.pip
275                 self.session.pip = self.session.instantiateDialog(PictureInPicture)
276                 self.session.pip.show()
277                 newservice = self.csel.servicelist.getCurrent()
278                 if self.session.pip.playService(newservice):
279                         self.session.pipshown = True
280                         self.session.pip.servicePath = self.csel.getCurrentServicePath()
281                         self.close(True)
282                 else:
283                         self.session.pipshown = False
284                         self.session.deleteDialog(self.session.pip)
285                         del self.session.pip
286                         self.session.openWithCallback(self.close, MessageBox, _("Could not open Picture in Picture"), MessageBox.TYPE_ERROR)
287
288         def addServiceToBouquetSelected(self):
289                 bouquets = self.csel.getBouquetList()
290                 if bouquets is None:
291                         cnt = 0
292                 else:
293                         cnt = len(bouquets)
294                 if cnt > 1: # show bouquet list
295                         self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, bouquets, self.addCurrentServiceToBouquet)
296                 elif cnt == 1: # add to only one existing bouquet
297                         self.addCurrentServiceToBouquet(bouquets[0][1], closeBouquetSelection = False)
298
299         def bouquetSelClosed(self, recursive):
300                 self.bsel = None
301                 if recursive:
302                         self.close(False)
303
304         def removeSatelliteServices(self):
305                 current = self.csel.getCurrentSelection()
306                 unsigned_orbpos = current.getUnsignedData(4) >> 16
307                 if unsigned_orbpos == 0xFFFF:
308                         eDVBDB.getInstance().removeServices(-65536) # 0xFFFF0000 as integer
309                 elif unsigned_orbpos == 0xEEEE:
310                         eDVBDB.getInstance().removeServices(-286392320) # 0xEEEE0000 as integer
311                 else:
312                         curpath = current.getPath()
313                         idx = curpath.find("satellitePosition == ")
314                         if idx != -1:
315                                 tmp = curpath[idx+21:]
316                                 idx = tmp.find(')')
317                                 if idx != -1:
318                                         satpos = int(tmp[:idx])
319                                         eDVBDB.getInstance().removeServices(-1, -1, -1, satpos)
320                 self.close()
321
322         def copyCurrentToBouquetList(self):
323                 self.csel.copyCurrentToBouquetList()
324                 self.close()
325
326         def removeBouquet(self):
327                 self.csel.removeBouquet()
328                 self.close()
329
330         def showMarkerInputBox(self):
331                 self.session.openWithCallback(self.markerInputCallback, InputBox, title=_("Please enter a name for the new marker"), text="markername", maxSize=False, visible_width = 56, type=Input.TEXT)
332
333         def markerInputCallback(self, marker):
334                 if marker is not None:
335                         self.csel.addMarker(marker)
336                 self.close()
337
338         def addCurrentServiceToBouquet(self, dest, closeBouquetSelection = True):
339                 self.csel.addServiceToBouquet(dest)
340                 if self.bsel is not None:
341                         self.bsel.close(True)
342                 else:
343                         self.close(closeBouquetSelection) # close bouquet selection
344
345         def removeCurrentService(self):
346                 self.csel.removeCurrentService()
347                 self.close()
348
349         def toggleMoveMode(self):
350                 self.csel.toggleMoveMode()
351                 self.close()
352
353         def renameSelectedEntry(self):
354                 cur = self.csel.getCurrentSelection()
355                 eServiceCenterInstance = eServiceCenter.getInstance()
356                 info = eServiceCenterInstance.info(cur)
357                 name = info and info.getName(cur) or ""
358                 #remove short name brakets
359                 name = name.replace('\xc2\x86', '').replace('\xc2\x87', '')
360                 if name:
361                         self.session.openWithCallback(self.csel.renameEntry, InputBox, title=_("Please enter a new name:"), text=name, maxSize=False, visible_width = 56, type=Input.TEXT)
362                 self.close()
363
364         def bouquetMarkStart(self):
365                 self.csel.startMarkedEdit(EDIT_BOUQUET)
366                 self.close()
367
368         def bouquetMarkEnd(self):
369                 self.csel.endMarkedEdit(abort=False)
370                 self.close()
371
372         def bouquetMarkAbort(self):
373                 self.csel.endMarkedEdit(abort=True)
374                 self.close()
375
376         def removeNewFoundFlag(self):
377                 eDVBDB.getInstance().removeFlag(self.csel.getCurrentSelection(), FLAG_SERVICE_NEW_FOUND)
378                 self.close()
379
380         def removeAllNewFoundFlags(self):
381                 curpath = self.csel.getCurrentSelection().getPath()
382                 idx = curpath.find("satellitePosition == ")
383                 if idx != -1:
384                         tmp = curpath[idx+21:]
385                         idx = tmp.find(')')
386                         if idx != -1:
387                                 satpos = int(tmp[:idx])
388                                 eDVBDB.getInstance().removeFlags(FLAG_SERVICE_NEW_FOUND, -1, -1, -1, satpos)
389                 self.close()
390
391         def editAlternativeServices(self):
392                 self.csel.startMarkedEdit(EDIT_ALTERNATIVES)
393                 self.close()
394
395         def showAlternativeServices(self):
396                 self.csel.enterPath(self.csel.getCurrentSelection())
397                 self.close()
398
399         def removeAlternativeServices(self):
400                 self.csel.removeAlternativeServices()
401                 self.close()
402
403         def addAlternativeServices(self):
404                 self.csel.addAlternativeServices()
405                 self.csel.startMarkedEdit(EDIT_ALTERNATIVES)
406                 self.close()
407
408         def execPlugin(self, plugin, service):
409                 plugin(self.session, service, csel=self.csel)
410
411
412 class SelectionEventInfo:
413         def __init__(self):
414                 self["ServiceEvent"] = ServiceEvent()
415                 self.servicelist.connectSelChanged(self.__selectionChanged)
416                 self.timer = eTimer()
417                 self.timer_conn = self.timer.timeout.connect(self.updateEventInfo)
418                 self.onShown.append(self.__selectionChanged)
419
420         def __selectionChanged(self):
421                 if self.execing:
422                         self.timer.start(100, True)
423
424         def updateEventInfo(self):
425                 cur = self.getCurrentSelection()
426                 self["ServiceEvent"].newService(cur)
427
428 class ChannelSelectionEPG:
429         def __init__(self):
430                 self["ChannelSelectEPGActions"] = ActionMap(["ChannelSelectEPGActions"],
431                         {
432                                 "showEPGList": self.showEPGList,
433                         })
434
435         def showEPGList(self):
436                 ref=self.getCurrentSelection()
437                 if ref:
438                         self.savedService = ref
439                         self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref, serviceChangeCB=self.changeServiceCB)
440
441         def SingleServiceEPGClosed(self, ret=False):
442                 self.setCurrentSelection(self.savedService)
443
444         def changeServiceCB(self, direction, epg):
445                 beg = self.getCurrentSelection()
446                 while True:
447                         if direction > 0:
448                                 self.moveDown()
449                         else:
450                                 self.moveUp()
451                         cur = self.getCurrentSelection()
452                         if cur == beg or not (cur.flags & eServiceReference.isMarker):
453                                 break
454                 epg.setService(ServiceReference(self.getCurrentSelection()))
455
456 class ChannelSelectionEdit:
457         def __init__(self):
458                 self.entry_marked = False
459                 self.movemode = False
460                 self.bouquet_mark_edit = OFF
461                 self.mutableList = None
462                 self.__marked = [ ]
463                 self.saved_title = None
464                 self.saved_root = None
465
466                 class ChannelSelectionEditActionMap(ActionMap):
467                         def __init__(self, csel, contexts = [ ], actions = { }, prio=0):
468                                 ActionMap.__init__(self, contexts, actions, prio)
469                                 self.csel = csel
470
471                         def action(self, contexts, action):
472                                 if action == "cancel":
473                                         self.csel.handleEditCancel()
474                                         return 0 # fall-trough
475                                 elif action == "ok":
476                                         return 0 # fall-trough
477                                 else:
478                                         return ActionMap.action(self, contexts, action)
479
480                 self["ChannelSelectEditActions"] = ChannelSelectionEditActionMap(self, ["ChannelSelectEditActions", "OkCancelActions"],
481                         {
482                                 "contextMenu": self.doContext,
483                         })
484
485         def getMutableList(self, root=eServiceReference()):
486                 if not self.mutableList is None:
487                         return self.mutableList
488                 serviceHandler = eServiceCenter.getInstance()
489                 if not root.valid():
490                         root=self.getRoot()
491                 list = root and serviceHandler.list(root)
492                 if list is not None:
493                         return list.startEdit()
494                 return None
495
496         def buildBouquetID(self, str):
497                 tmp = str.lower()
498                 name = ''
499                 for c in tmp:
500                         if (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9'):
501                                 name += c
502                         else:
503                                 name += '_'
504                 return name
505
506         def renameEntry(self, name):
507                 cur = self.servicelist.getCurrent()
508                 bouquet = self.getMutableList()
509                 if bouquet and name is not None:
510                         idx = self.servicelist.getCurrentIndex()
511                         if cur.flags & eServiceReference.mustDescent: # bouquet or service with alternatives
512                                 mutableList = self.getMutableList(cur)
513                                 mutableList.setListName(name)
514                                 mutableList.flushChanges()
515                         else:
516                                 cur.setName(name)
517                                 self.servicelist.addService(cur, True) # add the new entry above the current position
518                                 self.servicelist.removeCurrent()
519                                 if not self.servicelist.atEnd():
520                                         self.servicelist.moveUp()
521                                 bouquet.removeService(cur)
522                                 bouquet.addService(cur)
523                                 bouquet.moveService(cur, idx)
524                                 bouquet.flushChanges()
525
526         def addMarker(self, name):
527                 current = self.servicelist.getCurrent()
528                 mutableList = self.getMutableList()
529                 cnt = 0
530                 while mutableList:
531                         str = '1:64:%d:0:0:0:0:0:0:0::%s'%(cnt, name)
532                         ref = eServiceReference(str)
533                         if current and current.valid():
534                                 if not mutableList.addService(ref, current):
535                                         self.servicelist.addService(ref, True)
536                                         mutableList.flushChanges()
537                                         break
538                         elif not mutableList.addService(ref):
539                                 self.servicelist.addService(ref, True)
540                                 mutableList.flushChanges()
541                                 break
542                         cnt+=1
543
544         def addAlternativeServices(self):
545                 cur_service = ServiceReference(self.getCurrentSelection())
546                 root = self.getRoot()
547                 cur_root = root and ServiceReference(root)
548                 mutableBouquet = cur_root.list().startEdit()
549                 if mutableBouquet:
550                         name = cur_service.getServiceName()
551                         print "NAME", name
552                         if self.mode == MODE_TV:
553                                 str = '1:134:1:0:0:0:0:0:0:0:FROM BOUQUET \"alternatives.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(name))
554                         else:
555                                 str = '1:134:2:0:0:0:0:0:0:0:FROM BOUQUET \"alternatives.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(name))
556                         new_ref = ServiceReference(str)
557                         if not mutableBouquet.addService(new_ref.ref, cur_service.ref):
558                                 mutableBouquet.removeService(cur_service.ref)
559                                 mutableBouquet.flushChanges()
560                                 eDVBDB.getInstance().reloadBouquets()
561                                 mutableAlternatives = new_ref.list().startEdit()
562                                 if mutableAlternatives:
563                                         mutableAlternatives.setListName(name)
564                                         if mutableAlternatives.addService(cur_service.ref):
565                                                 print "add", cur_service.ref.toString(), "to new alternatives failed"
566                                         mutableAlternatives.flushChanges()
567                                         self.servicelist.removeCurrent()
568                                         self.servicelist.addService(new_ref.ref, True)
569                                 else:
570                                         print "get mutable list for new created alternatives failed"
571                         else:
572                                 print "add", str, "to", cur_root.getServiceName(), "failed"
573                 else:
574                         print "bouquetlist is not editable"
575
576         def addBouquet(self, bName, services):
577                 serviceHandler = eServiceCenter.getInstance()
578                 mutableBouquetList = serviceHandler.list(self.bouquet_root).startEdit()
579                 if mutableBouquetList:
580                         if self.mode == MODE_TV:
581                                 bName += " (TV)"
582                                 str = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(bName))
583                         else:
584                                 bName += " (Radio)"
585                                 str = '1:7:2:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(bName))
586                         new_bouquet_ref = eServiceReference(str)
587                         if not mutableBouquetList.addService(new_bouquet_ref):
588                                 mutableBouquetList.flushChanges()
589                                 eDVBDB.getInstance().reloadBouquets()
590                                 mutableBouquet = serviceHandler.list(new_bouquet_ref).startEdit()
591                                 if mutableBouquet:
592                                         mutableBouquet.setListName(bName)
593                                         if services is not None:
594                                                 for service in services:
595                                                         if mutableBouquet.addService(service):
596                                                                 print "add", service.toString(), "to new bouquet failed"
597                                         mutableBouquet.flushChanges()
598                                 else:
599                                         print "get mutable list for new created bouquet failed"
600                                 # do some voodoo to check if current_root is equal to bouquet_root
601                                 cur_root = self.getRoot();
602                                 str1 = cur_root and cur_root.toString()
603                                 pos1 = str1 and str1.find("FROM BOUQUET") or -1
604                                 pos2 = self.bouquet_rootstr.find("FROM BOUQUET")
605                                 if pos1 != -1 and pos2 != -1 and str1[pos1:] == self.bouquet_rootstr[pos2:]:
606                                         self.servicelist.addService(new_bouquet_ref)
607                         else:
608                                 print "add", str, "to bouquets failed"
609                 else:
610                         print "bouquetlist is not editable"
611
612         def copyCurrentToBouquetList(self):
613                 provider = ServiceReference(self.getCurrentSelection())
614                 providerName = provider.getServiceName()
615                 serviceHandler = eServiceCenter.getInstance()
616                 services = serviceHandler.list(provider.ref)
617                 self.addBouquet(providerName, services and services.getContent('R', True))
618
619         def removeAlternativeServices(self):
620                 cur_service = ServiceReference(self.getCurrentSelection())
621                 root = self.getRoot()
622                 cur_root = root and ServiceReference(root)
623                 list = cur_service.list()
624                 first_in_alternative = list and list.getNext()
625                 if first_in_alternative:
626                         edit_root = cur_root and cur_root.list().startEdit()
627                         if edit_root:
628                                 if not edit_root.addService(first_in_alternative, cur_service.ref):
629                                         self.servicelist.addService(first_in_alternative, True)
630                                         self.servicelist.setCurrent(cur_service.ref)
631                                 else:
632                                         print "couldn't add first alternative service to current root"
633                         else:
634                                 print "couldn't edit current root!!"
635                 else:
636                         print "remove empty alternative list !!"
637                 self.removeBouquet()
638                 if first_in_alternative:
639                         self.servicelist.setCurrent(first_in_alternative) 
640
641         def removeBouquet(self):
642                 refstr = self.getCurrentSelection().toString()
643                 print "removeBouquet", refstr
644                 self.bouquetNumOffsetCache = { }
645                 pos = refstr.find('FROM BOUQUET "')
646                 filename = None
647                 if pos != -1:
648                         refstr = refstr[pos+14:]
649                         pos = refstr.find('"')
650                         if pos != -1:
651                                 filename = eEnv.resolve('${sysconfdir}/enigma2/') + refstr[:pos]
652                 self.removeCurrentService()
653                 try:
654                         if filename is not None:
655                                 remove(filename)
656                 except OSError:
657                         print "error during remove of", filename
658
659 #  multiple marked entry stuff ( edit mode, later multiepg selection )
660         def startMarkedEdit(self, type):
661                 self.savedPath = self.servicePath[:]
662                 if type == EDIT_ALTERNATIVES:
663                         self.enterPath(self.getCurrentSelection())
664                 self.mutableList = self.getMutableList()
665                 # add all services from the current list to internal marked set in listboxservicecontent
666                 self.clearMarks() # this clears the internal marked set in the listboxservicecontent
667                 self.saved_title = self.getTitle()
668                 pos = self.saved_title.find(')')
669                 new_title = self.saved_title[:pos+1]
670                 if type == EDIT_ALTERNATIVES:
671                         self.bouquet_mark_edit = EDIT_ALTERNATIVES
672                         new_title += ' ' + _("[alternative edit]")
673                 else:
674                         self.bouquet_mark_edit = EDIT_BOUQUET
675                         if config.usage.multibouquet.value:
676                                 new_title += ' ' + _("[bouquet edit]")
677                         else:
678                                 new_title += ' ' + _("[favourite edit]")
679                 self.setTitle(new_title)
680                 self.__marked = self.servicelist.getRootServices()
681                 for x in self.__marked:
682                         self.servicelist.addMarked(eServiceReference(x))
683                 self.showAllServices()
684
685         def endMarkedEdit(self, abort):
686                 if not abort and self.mutableList is not None:
687                         self.bouquetNumOffsetCache = { }
688                         new_marked = set(self.servicelist.getMarked())
689                         old_marked = set(self.__marked)
690                         removed = old_marked - new_marked
691                         added = new_marked - old_marked
692                         changed = False
693                         for x in removed:
694                                 changed = True
695                                 self.mutableList.removeService(eServiceReference(x))
696                         for x in added:
697                                 changed = True
698                                 self.mutableList.addService(eServiceReference(x))
699                         if changed:
700                                 self.mutableList.flushChanges()
701                 self.__marked = []
702                 self.clearMarks()
703                 self.bouquet_mark_edit = OFF
704                 self.mutableList = None
705                 self.setTitle(self.saved_title)
706                 self.saved_title = None
707                 # self.servicePath is just a reference to servicePathTv or Radio...
708                 # so we never ever do use the asignment operator in self.servicePath
709                 del self.servicePath[:] # remove all elements
710                 self.servicePath += self.savedPath # add saved elements
711                 del self.savedPath
712                 self.setRoot(self.servicePath[-1])
713
714         def clearMarks(self):
715                 self.servicelist.clearMarks()
716
717         def doMark(self):
718                 ref = self.servicelist.getCurrent()
719                 if self.servicelist.isMarked(ref):
720                         self.servicelist.removeMarked(ref)
721                 else:
722                         self.servicelist.addMarked(ref)
723
724         def removeCurrentService(self):
725                 ref = self.servicelist.getCurrent()
726                 mutableList = self.getMutableList()
727                 if ref.valid() and mutableList is not None:
728                         if not mutableList.removeService(ref):
729                                 self.bouquetNumOffsetCache = { }
730                                 mutableList.flushChanges() #FIXME dont flush on each single removed service
731                                 self.servicelist.removeCurrent()
732
733         def addServiceToBouquet(self, dest, service=None):
734                 mutableList = self.getMutableList(dest)
735                 if not mutableList is None:
736                         if service is None: #use current selected service
737                                 service = self.servicelist.getCurrent()
738                         if not mutableList.addService(service):
739                                 self.bouquetNumOffsetCache = { }
740                                 mutableList.flushChanges()
741                                 # do some voodoo to check if current_root is equal to dest
742                                 cur_root = self.getRoot();
743                                 str1 = cur_root and cur_root.toString() or -1
744                                 str2 = dest.toString()
745                                 pos1 = str1.find("FROM BOUQUET")
746                                 pos2 = str2.find("FROM BOUQUET")
747                                 if pos1 != -1 and pos2 != -1 and str1[pos1:] == str2[pos2:]:
748                                         self.servicelist.addService(service)
749
750         def toggleMoveMode(self):
751                 if self.movemode:
752                         if self.entry_marked:
753                                 self.toggleMoveMarked() # unmark current entry
754                         self.movemode = False
755                         self.pathChangeDisabled = False # re-enable path change
756                         self.mutableList.flushChanges() # FIXME add check if changes was made
757                         self.mutableList = None
758                         self.setTitle(self.saved_title)
759                         self.saved_title = None
760                         cur_root = self.getRoot()
761                         if cur_root and cur_root == self.bouquet_root:
762                                 self.bouquetNumOffsetCache = { }
763                 else:
764                         self.mutableList = self.getMutableList()
765                         self.movemode = True
766                         self.pathChangeDisabled = True # no path change allowed in movemode
767                         self.saved_title = self.getTitle()
768                         new_title = self.saved_title
769                         pos = self.saved_title.find(')')
770                         new_title = self.saved_title[:pos+1] + ' ' + _("[move mode]") + self.saved_title[pos+1:]
771                         self.setTitle(new_title);
772
773         def handleEditCancel(self):
774                 if self.movemode: #movemode active?
775                         if self.entry_marked:
776                                 self.channelSelected() # unmark
777                         self.toggleMoveMode() # disable move mode
778                 elif self.bouquet_mark_edit != OFF:
779                         self.endMarkedEdit(True) # abort edit mode
780
781         def toggleMoveMarked(self):
782                 if self.entry_marked:
783                         self.servicelist.setCurrentMarked(False)
784                         self.entry_marked = False
785                 else:
786                         self.servicelist.setCurrentMarked(True)
787                         self.entry_marked = True
788
789         def doContext(self):
790                 self.session.openWithCallback(self.exitContext, ChannelContextMenu, self)
791
792         def exitContext(self, close = False):
793                 if close:
794                         self.cancel()
795
796 MODE_TV = 0
797 MODE_RADIO = 1
798
799 # type 1 = digital television service
800 # type 4 = nvod reference service (NYI)
801 # type 17 = MPEG-2 HD digital television service
802 # type 22 = advanced codec SD digital television
803 # type 24 = advanced codec SD NVOD reference service (NYI)
804 # type 25 = advanced codec HD digital television
805 # type 27 = advanced codec HD NVOD reference service (NYI)
806 # type 2 = digital radio sound service
807 # type 10 = advanced codec digital radio sound service
808
809 service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 22) || (type == 25) || (type == 31) || (type == 134) || (type == 195)'
810 service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2) || (type == 10)'
811
812 class ChannelSelectionBase(Screen):
813         ALLOW_SUSPEND = True
814
815         def __init__(self, session):
816                 Screen.__init__(self, session)
817
818                 self["key_red"] = Button("")
819                 self["key_green"] = Button(_("Satellites"))
820                 self["key_yellow"] = Button(_("Providers"))
821                 self["key_blue"] = Button(_("Favourites"))
822
823                 self["list"] = ServiceList(session)
824                 self.servicelist = self["list"]
825
826                 self.numericalTextInput = NumericalTextInput()
827                 self.numericalTextInput.setUseableChars(u'1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ')
828
829                 self.servicePathTV = [ ]
830                 self.servicePathRadio = [ ]
831                 self.servicePath = [ ]
832                 self.rootChanged = False
833                 self.bouquet_root = None
834
835                 self.mode = MODE_TV
836
837                 self.pathChangeDisabled = False
838
839                 self.bouquetNumOffsetCache = { }
840                 self.onRootChanged = []
841
842                 self["ChannelSelectBaseActions"] = NumberActionMap(["ChannelSelectBaseActions", "NumberActions", "InputAsciiActions"],
843                         {
844                                 "showFavourites": self.showFavourites,
845                                 "showAllServices": self._openPlugins,
846                                 "showProviders": self.showProviders,
847                                 "showSatellites": self.showSatellites,
848                                 "nextBouquet": self.nextBouquet,
849                                 "prevBouquet": self.prevBouquet,
850                                 "nextMarker": self.nextMarker,
851                                 "prevMarker": self.prevMarker,
852                                 "gotAsciiCode": self.keyAsciiCode,
853                                 "selectServiceDown": None, #avoid debug output warning
854                                 "selectServiceUp": None, #avoid debug output warning
855                                 "selectServicePageDown": None, #avoid debug output warning
856                                 "selectServicePageUp": None, #avoid debug output warning
857                                 "1": self.keyNumberGlobal,
858                                 "2": self.keyNumberGlobal,
859                                 "3": self.keyNumberGlobal,
860                                 "4": self.keyNumberGlobal,
861                                 "5": self.keyNumberGlobal,
862                                 "6": self.keyNumberGlobal,
863                                 "7": self.keyNumberGlobal,
864                                 "8": self.keyNumberGlobal,
865                                 "9": self.keyNumberGlobal,
866                                 "0": self.keyNumber0
867                         })
868                 self.setTitle(_("Channel Selection"))
869                 self._pluginList = []
870                 self._checkPlugins()
871                 self.recallBouquetMode()
872
873         def getCurrentEventNow(self):
874                 serviceref = self.servicelist.getCurrent()
875                 event = None
876                 try:
877                         epg = eEPGCache.getInstance()
878                         event = epg.lookupEventTime(serviceref, -1, 0)
879                         if event is None:
880                                 info = eServiceCenter.getInstance().info(serviceref)
881                                 event = info.getEvent(0)
882                 except:
883                         pass
884                 return event
885
886         def _checkPlugins(self):
887                 self._pluginList = [(p.name, p, False) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_CHANNEL_SELECTION_RED)]
888                 self._pluginList.append((_("All"), self.showAllServices, True))
889                 if self._pluginList:
890                         if len(self._pluginList) > 1:
891                                 self["key_red"].setText(_("More ..."))
892                         else:
893                                 self["key_red"].setText(self._pluginList[0][0])
894                 else:
895                         self["key_red"].setText("")
896
897         def _openPlugins(self):
898                 if self._pluginList:
899                         if len(self._pluginList) > 1:
900                                 self.session.openWithCallback(self._onPluginSelected, ChoiceBox, list=self._pluginList, windowTitle=_("More ..."))
901                         else:
902                                 self._onPluginSelected(self._pluginList[0])
903
904         def _onPluginSelected(self, p=None):
905                 noargs = p and p[2]
906                 fnc = p and p[1]
907                 if not fnc:
908                         return
909                 if noargs: #noarg for multiepgcallback backwards compat
910                         fnc()
911                         return
912
913                 event = self.getCurrentEventNow()
914                 if not event:
915                         self.session.toastManager.showToast(_("This feature requires valid EPG!"))
916                         return
917                 fnc(self.session, event, self.servicelist.getCurrent())
918
919         def getBouquetNumOffset(self, bouquet):
920                 if not config.usage.multibouquet.value:
921                         return 0
922                 str = bouquet.toString()
923                 offsetCount = 0
924                 if not self.bouquetNumOffsetCache.has_key(str):
925                         serviceHandler = eServiceCenter.getInstance()
926                         bouquetlist = serviceHandler.list(self.bouquet_root)
927                         if not bouquetlist is None:
928                                 while True:
929                                         bouquetIterator = bouquetlist.getNext()
930                                         if not bouquetIterator.valid(): #end of list
931                                                 break
932                                         self.bouquetNumOffsetCache[bouquetIterator.toString()]=offsetCount
933                                         if not (bouquetIterator.flags & eServiceReference.isDirectory):
934                                                 continue
935                                         servicelist = serviceHandler.list(bouquetIterator)
936                                         if not servicelist is None:
937                                                 while True:
938                                                         serviceIterator = servicelist.getNext()
939                                                         if not serviceIterator.valid(): #check if end of list
940                                                                 break
941                                                         playable = not (serviceIterator.flags & (eServiceReference.isDirectory|eServiceReference.isMarker))
942                                                         if playable:
943                                                                 offsetCount += 1
944                 return self.bouquetNumOffsetCache.get(str, offsetCount)
945
946         def recallBouquetMode(self):
947                 fixServicePath = self.servicePath and self.servicePath[0] == self.bouquet_root
948                 if self.mode == MODE_TV:
949                         self.service_types = service_types_tv
950                         if config.usage.multibouquet.value:
951                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.tv" ORDER BY bouquet'
952                         else:
953                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)
954                 else:
955                         self.service_types = service_types_radio
956                         if config.usage.multibouquet.value:
957                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.radio" ORDER BY bouquet'
958                         else:
959                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(self.service_types)
960
961                 self.bouquet_root = eServiceReference(self.bouquet_rootstr)
962                 if fixServicePath:
963                         self.servicePath = []
964                         self.servicePath.append(self.bouquet_root)
965
966         def setTvMode(self):
967                 self.mode = MODE_TV
968                 self.servicePath = self.servicePathTV
969                 self.recallBouquetMode()
970                 title = self.getTitle()
971                 pos = title.find(" (")
972                 if pos != -1:
973                         title = title[:pos]
974                 title += " (TV)"
975                 self.setTitle(title)
976
977         def setRadioMode(self):
978                 self.mode = MODE_RADIO
979                 self.servicePath = self.servicePathRadio
980                 self.recallBouquetMode()
981                 title = self.getTitle()
982                 pos = title.find(" (")
983                 if pos != -1:
984                         title = title[:pos]
985                 title += " (Radio)"
986                 self.setTitle(title)
987
988         def setRoot(self, root, justSet=False):
989                 setModeFavourites = False
990
991                 serviceHandler = eServiceCenter.getInstance()
992                 list = root and serviceHandler.list(root)
993                 if list is not None:
994                         if list.startEdit():
995                                 ref = list.getNext()
996                                 setModeFavourites = not (ref.flags & eServiceReference.isDirectory)
997
998                 if setModeFavourites:
999                         self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
1000                         self.servicelist.setNumberOffset(self.getBouquetNumOffset(root))
1001                 else:
1002                         self.servicelist.setMode(ServiceList.MODE_NORMAL)
1003
1004                 self.servicelist.setRoot(root, justSet)
1005                 self.rootChanged = True
1006                 self.buildTitleString()
1007
1008         def removeModeStr(self, str):
1009                 if self.mode == MODE_TV:
1010                         pos = str.find(' (TV)')
1011                 else:
1012                         pos = str.find(' (Radio)')
1013                 if pos != -1:
1014                         return str[:pos]
1015                 return str
1016
1017         def getServiceName(self, ref):
1018                 str = self.removeModeStr(ServiceReference(ref).getServiceName())
1019                 if not str:
1020                         pathstr = ref.getPath()
1021                         if 'FROM PROVIDERS' in pathstr:
1022                                 return _("Providers")
1023                         if 'FROM SATELLITES' in pathstr:
1024                                 return _("Satellites")
1025                         if ') ORDER BY name' in pathstr:
1026                                 return _("All")
1027                 return str
1028
1029         def buildTitleString(self):
1030                 titleStr = self.getTitle()
1031                 pos = titleStr.find(']')
1032                 if pos == -1:
1033                         pos = titleStr.find(')')
1034                 if pos != -1:
1035                         titleStr = titleStr[:pos+1]
1036                         Len = len(self.servicePath)
1037                         if Len > 0:
1038                                 base_ref = self.servicePath[0]
1039                                 if Len > 1:
1040                                         end_ref = self.servicePath[Len-1]
1041                                 else:
1042                                         end_ref = None
1043                                 nameStr = self.getServiceName(base_ref)
1044                                 titleStr += ' ' + nameStr
1045                                 if end_ref is not None:
1046                                         if Len > 2:
1047                                                 titleStr += '/../'
1048                                         else:
1049                                                 titleStr += '/'
1050                                         nameStr = self.getServiceName(end_ref)
1051                                         titleStr += nameStr
1052                                 self.setTitle(titleStr)
1053
1054         def moveUp(self):
1055                 self.servicelist.moveUp()
1056
1057         def moveDown(self):
1058                 self.servicelist.moveDown()
1059
1060         def clearPath(self):
1061                 del self.servicePath[:]
1062
1063         def enterPath(self, ref, justSet=False):
1064                 self.servicePath.append(ref)
1065                 self.setRoot(ref, justSet)
1066                 for fnc in self.onRootChanged:
1067                         fnc(ref)
1068
1069         def pathUp(self, justSet=False):
1070                 prev = self.servicePath.pop()
1071                 if self.servicePath:
1072                         current = self.servicePath[-1]
1073                         self.setRoot(current, justSet)
1074                         if not justSet:
1075                                 self.setCurrentSelection(prev)
1076                 return prev
1077
1078         def isBasePathEqual(self, ref):
1079                 if len(self.servicePath) > 1 and self.servicePath[0] == ref:
1080                         return True
1081                 return False
1082
1083         def isPrevPathEqual(self, ref):
1084                 length = len(self.servicePath)
1085                 if length > 1 and self.servicePath[length-2] == ref:
1086                         return True
1087                 return False
1088
1089         def preEnterPath(self, refstr):
1090                 return False
1091
1092         def showAllServices(self):
1093                 if not self.pathChangeDisabled:
1094                         refstr = '%s ORDER BY name'%(self.service_types)
1095                         if not self.preEnterPath(refstr):
1096                                 ref = eServiceReference(refstr)
1097                                 currentRoot = self.getRoot()
1098                                 if currentRoot is None or currentRoot != ref:
1099                                         self.clearPath()
1100                                         self.enterPath(ref)
1101
1102         def showSatellites(self):
1103                 if not self.pathChangeDisabled:
1104                         refstr = '%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)
1105                         if not self.preEnterPath(refstr):
1106                                 ref = eServiceReference(refstr)
1107                                 justSet=False
1108                                 prev = None
1109
1110                                 if self.isBasePathEqual(ref):
1111                                         if self.isPrevPathEqual(ref):
1112                                                 justSet=True
1113                                         prev = self.pathUp(justSet)
1114                                 else:
1115                                         currentRoot = self.getRoot()
1116                                         if currentRoot is None or currentRoot != ref:
1117                                                 justSet=True
1118                                                 self.clearPath()
1119                                                 self.enterPath(ref, True)
1120                                 if justSet:
1121                                         serviceHandler = eServiceCenter.getInstance()
1122                                         servicelist = serviceHandler.list(ref)
1123                                         if not servicelist is None:
1124                                                 self.servicelist.setMode(self.servicelist.MODE_NORMAL)
1125                                                 while True:
1126                                                         service = servicelist.getNext()
1127                                                         if not service.valid(): #check if end of list
1128                                                                 break
1129                                                         unsigned_orbpos = service.getUnsignedData(4) >> 16
1130                                                         orbpos = service.getData(4) >> 16
1131                                                         if orbpos < 0:
1132                                                                 orbpos += 3600
1133                                                         if service.getPath().find("FROM PROVIDER") != -1:
1134                                                                 service_type = _("Providers")
1135                                                         elif service.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
1136                                                                 service_type = _("New")
1137                                                         elif service.getPath().find("numCAIDs") != -1:
1138                                                                 service_type = _("Services") + " FTA"
1139                                                         else:
1140                                                                 service_type = _("Services")
1141                                                         try:
1142                                                                 # why we need this cast?
1143                                                                 service_name = str(nimmanager.getSatDescription(orbpos))
1144                                                         except:
1145                                                                 if unsigned_orbpos == 0xFFFF: #Cable
1146                                                                         service_name = _("Cable")
1147                                                                 elif unsigned_orbpos == 0xEEEE: #Terrestrial
1148                                                                         service_name = _("Terrestrial")
1149                                                                 else:
1150                                                                         if orbpos > 1800: # west
1151                                                                                 orbpos = 3600 - orbpos
1152                                                                                 h = _("W")
1153                                                                         else:
1154                                                                                 h = _("E")
1155                                                                         service_name = ("%d.%d" + h) % (orbpos / 10, orbpos % 10)
1156                                                         service.setName("%s - %s" % (service_name, service_type))
1157                                                         self.servicelist.addService(service)
1158                                                 self.servicelist.finishFill()
1159                                                 cur_ref = self.session.nav.getCurrentlyPlayingServiceReference()
1160                                                 if cur_ref:
1161                                                         pos = self.service_types.rfind(':')
1162                                                         refstr = '%s (channelID == %08x%04x%04x) && %s ORDER BY name' %(self.service_types[:pos+1],
1163                                                                 cur_ref.getUnsignedData(4), # NAMESPACE
1164                                                                 cur_ref.getUnsignedData(2), # TSID
1165                                                                 cur_ref.getUnsignedData(3), # ONID
1166                                                                 self.service_types[pos+1:])
1167                                                         ref = eServiceReference(refstr)
1168                                                         ref.flags |= eServiceReference.sort1 # needed for sort
1169                                                         ref.setName(_("Current Transponder"))
1170                                                         self.servicelist.addService(ref, True)
1171                                                         self.servicelist.moveUp()
1172                                                 if prev is not None:
1173                                                         self.setCurrentSelection(prev)
1174
1175         def showProviders(self):
1176                 if not self.pathChangeDisabled:
1177                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
1178                         if not self.preEnterPath(refstr):
1179                                 ref = eServiceReference(refstr)
1180                                 if self.isBasePathEqual(ref):
1181                                         self.pathUp()
1182                                 else:
1183                                         currentRoot = self.getRoot()
1184                                         if currentRoot is None or currentRoot != ref:
1185                                                 self.clearPath()
1186                                                 self.enterPath(ref)
1187
1188         def changeBouquet(self, direction):
1189                 if not self.pathChangeDisabled:
1190                         if len(self.servicePath) > 1:
1191                                 #when enter satellite root list we must do some magic stuff..
1192                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
1193                                 if self.isBasePathEqual(ref):
1194                                         self.showSatellites()
1195                                 else:
1196                                         self.pathUp()
1197                                 if direction < 0:
1198                                         self.moveUp()
1199                                 else:
1200                                         self.moveDown()
1201                                 ref = self.getCurrentSelection()
1202                                 self.enterPath(ref)
1203
1204         def inBouquet(self):
1205                 if self.servicePath and self.servicePath[0] == self.bouquet_root:
1206                         return True
1207                 return False
1208
1209         def atBegin(self):
1210                 return self.servicelist.atBegin()
1211
1212         def atEnd(self):
1213                 return self.servicelist.atEnd()
1214
1215         def nextBouquet(self):
1216                 self.changeBouquet(+1)
1217
1218         def prevBouquet(self):
1219                 self.changeBouquet(-1)
1220
1221         def showFavourites(self):
1222                 if not self.pathChangeDisabled:
1223                         if not self.preEnterPath(self.bouquet_rootstr):
1224                                 if self.isBasePathEqual(self.bouquet_root):
1225                                         self.pathUp()
1226                                 else:
1227                                         currentRoot = self.getRoot()
1228                                         if currentRoot is None or currentRoot != self.bouquet_root:
1229                                                 self.clearPath()
1230                                                 self.enterPath(self.bouquet_root)
1231
1232         def keyNumberGlobal(self, number):
1233                 unichar = self.numericalTextInput.getKey(number)
1234                 charstr = unichar.encode("utf-8")
1235                 if len(charstr) == 1:
1236                         self.servicelist.moveToChar(charstr[0])
1237
1238         def keyAsciiCode(self):
1239                 unichar = unichr(getPrevAsciiCode())
1240                 charstr = unichar.encode("utf-8")
1241                 if len(charstr) == 1:
1242                         self.servicelist.moveToChar(charstr[0])
1243
1244         def getRoot(self):
1245                 return self.servicelist.getRoot()
1246
1247         def getCurrentSelection(self):
1248                 return self.servicelist.getCurrent()
1249
1250         def setCurrentSelection(self, service):
1251                 self.servicelist.setCurrent(service)
1252
1253         def getBouquetList(self):
1254                 bouquets = [ ]
1255                 serviceHandler = eServiceCenter.getInstance()
1256                 if config.usage.multibouquet.value:
1257                         list = serviceHandler.list(self.bouquet_root)
1258                         if list:
1259                                 while True:
1260                                         s = list.getNext()
1261                                         if not s.valid():
1262                                                 break
1263                                         if s.flags & eServiceReference.isDirectory:
1264                                                 info = serviceHandler.info(s)
1265                                                 if info:
1266                                                         bouquets.append((info.getName(s), s))
1267                                 return bouquets
1268                 else:
1269                         info = serviceHandler.info(self.bouquet_root)
1270                         if info:
1271                                 bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
1272                         return bouquets
1273                 return None
1274
1275         def keyNumber0(self, num):
1276                 if len(self.servicePath) > 1:
1277                         self.keyGoUp()
1278                 else:
1279                         self.keyNumberGlobal(num)
1280
1281         def keyGoUp(self):
1282                 if len(self.servicePath) > 1:
1283                         if self.isBasePathEqual(self.bouquet_root):
1284                                 self.showFavourites()
1285                         else:
1286                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
1287                                 if self.isBasePathEqual(ref):
1288                                         self.showSatellites()
1289                                 else:
1290                                         ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
1291                                         if self.isBasePathEqual(ref):
1292                                                 self.showProviders()
1293                                         else:
1294                                                 self.showAllServices()
1295
1296         def nextMarker(self):
1297                 self.servicelist.moveToNextMarker()
1298
1299         def prevMarker(self):
1300                 self.servicelist.moveToPrevMarker()
1301
1302 #config for lastservice
1303 config.tv = ConfigSubsection()
1304 config.tv.lastservice = ConfigText()
1305 config.tv.lastroot = ConfigText()
1306 config.radio = ConfigSubsection()
1307 config.radio.lastservice = ConfigText()
1308 config.radio.lastroot = ConfigText()
1309 config.servicelist = ConfigSubsection()
1310 config.servicelist.lastmode = ConfigText(default = "tv")
1311
1312 from Components.StreamServerControl import streamServerControl
1313 class ChannelSelectionEncoderService(object):
1314         def __init__(self):
1315                 self["EncoderActions"] = ActionMap(["ChannelSelectionEncoderActions"],
1316                         {
1317                                 "setEncoderService" : self._setEncoderService
1318                         })
1319
1320         def _setEncoderService(self):
1321                 ref = self.getCurrentSelection()
1322                 if ref:
1323                         res = streamServerControl.setEncoderService(ref)
1324                         infotext = ""
1325                         if res == streamServerControl.ENCODER_SERVICE_SET:
1326                                 infotext = _("Encoder service now set to {0}").format(ref.getName())
1327                         elif res == streamServerControl.ENCODER_SERVICE_ALREADY_ACTIVE:
1328                                 infotext = _("Encoder service was already set to {0}").format(ref.getName())
1329                         elif res == streamServerControl.ENCODER_SERVICE_INVALID_MODE:
1330                                 infotext = _("Encoder service can only be set when in TV-Services mode!")
1331                         elif res == streamServerControl.ENCODER_SERVICE_INSUFFICIENT_RESOURCES:
1332                                 infotext = _("Setting new encoder service to {0} failed! (Insufficient resources)".format(ref.getName()))
1333                         else:
1334                                 infotext = _("Setting new encoder service to {0} failed!".format(ref.getName()))
1335                         if infotext:
1336                                 self.session.toastManager.showToast(infotext)
1337
1338 HISTORYSIZE = 20
1339
1340 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, SelectionEventInfo, ChannelSelectionEncoderService):
1341         initialized = NoSave(ConfigBoolean(default = False))
1342
1343         def __init__(self, session):
1344                 ChannelSelectionBase.__init__(self,session)
1345                 ChannelSelectionEdit.__init__(self)
1346                 ChannelSelectionEPG.__init__(self)
1347                 SelectionEventInfo.__init__(self)
1348                 ChannelSelectionEncoderService.__init__(self)
1349
1350                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1351                         {
1352                                 "cancel": self.cancel,
1353                                 "ok": self.channelSelected,
1354                                 "keyRadio": self.setModeRadio,
1355                                 "keyTV": self.setModeTv,
1356                         })
1357
1358                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1359                         {
1360                                 iPlayableService.evStart: self.__evServiceStart,
1361                                 iPlayableService.evEnd: self.__evServiceEnd
1362                         })
1363
1364                 self.lastChannelRootTimer = eTimer()
1365                 self.lastChannelRootTimer_conn = self.lastChannelRootTimer.timeout.connect(self.__onCreate)
1366                 self.lastChannelRootTimer.start(100,True)
1367
1368                 self.history_tv = [ ]
1369                 self.history_radio = [ ]
1370                 self.history = self.history_tv
1371                 self.history_pos = 0
1372
1373                 self.lastservice = config.tv.lastservice
1374                 self.lastroot = config.tv.lastroot
1375                 self.revertMode = None
1376                 config.usage.multibouquet.addNotifier(self.multibouquet_config_changed)
1377                 self.new_service_played = False
1378                 self.onExecBegin.append(self.__execBegin)
1379
1380         def __execBegin(self):
1381                 self.setKeyboardModeAscii()
1382
1383         def multibouquet_config_changed(self, val):
1384                 self.recallBouquetMode()
1385
1386         def __evServiceStart(self):
1387                 service = self.session.nav.getCurrentService()
1388                 if service:
1389                         info = service.info()
1390                         if info:
1391                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1392                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1393
1394         def __evServiceEnd(self):
1395                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1396
1397         def setMode(self):
1398                 self.rootChanged = True
1399                 self.restoreRoot()
1400                 lastservice=eServiceReference(self.lastservice.value)
1401                 if lastservice.valid():
1402                         self.setCurrentSelection(lastservice)
1403
1404         def setModeTv(self):
1405                 if self.revertMode is None and config.servicelist.lastmode.value == "radio":
1406                         self.revertMode = MODE_RADIO
1407                 self.history = self.history_tv
1408                 self.lastservice = config.tv.lastservice
1409                 self.lastroot = config.tv.lastroot
1410                 config.servicelist.lastmode.value = "tv"
1411                 self.setTvMode()
1412                 self.setMode()
1413
1414         def setModeRadio(self):
1415                 if self.revertMode is None and config.servicelist.lastmode.value == "tv":
1416                         self.revertMode = MODE_TV
1417                 if config.usage.e1like_radio_mode.value:
1418                         self.history = self.history_radio
1419                         self.lastservice = config.radio.lastservice
1420                         self.lastroot = config.radio.lastroot
1421                         config.servicelist.lastmode.value = "radio"
1422                         self.setRadioMode()
1423                         self.setMode()
1424
1425         def __onCreate(self):
1426                 if config.usage.e1like_radio_mode.value:
1427                         if config.servicelist.lastmode.value == "tv":
1428                                 self.setModeTv()
1429                         else:
1430                                 self.setModeRadio()
1431                 else:
1432                         self.setModeTv()
1433                 lastservice=eServiceReference(self.lastservice.value)
1434                 if lastservice.valid():
1435                         if not Screens.Standby.inStandby:
1436                                 self.zap()
1437                         else:
1438                                 Screens.Standby.inStandby.onClose.append(self.zap)
1439                 ChannelSelection.initialized.value = True
1440
1441         def channelSelected(self):
1442                 ref = self.getCurrentSelection()
1443                 if self.movemode:
1444                         self.toggleMoveMarked()
1445                 elif (ref.flags & 7) == 7:
1446                         self.enterPath(ref)
1447                 elif self.bouquet_mark_edit != OFF:
1448                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1449                                 self.doMark()
1450                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1451                         root = self.getRoot()
1452                         if not root or not (root.flags & eServiceReference.isGroup):
1453                                 self.zap()
1454                                 self.close(ref)
1455
1456         #called from infoBar and channelSelected
1457         def zap(self, nref=None, root=None):
1458                 self.revertMode=None
1459                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1460                 if not nref:
1461                         nref = self.getCurrentSelection()
1462                 if root:
1463                         if not self.preEnterPath(root):
1464                                 self.clearPath()
1465                                 self.enterPath(eServiceReference(root))
1466                 if ref is None or ref != nref:
1467                         self.new_service_played = True
1468                         self.session.nav.playService(nref)
1469                         self.saveRoot()
1470                         self.saveChannel(nref)
1471                         config.servicelist.lastmode.save()
1472                         self.addToHistory(nref)
1473
1474         def newServicePlayed(self):
1475                 ret = self.new_service_played
1476                 self.new_service_played = False
1477                 return ret
1478
1479         def addToHistory(self, ref):
1480                 if self.servicePath is not None:
1481                         tmp=self.servicePath[:]
1482                         tmp.append(ref)
1483                         try:
1484                                 del self.history[self.history_pos+1:]
1485                         except:
1486                                 pass
1487                         self.history.append(tmp)
1488                         hlen = len(self.history)
1489                         if hlen > HISTORYSIZE:
1490                                 del self.history[0]
1491                                 hlen -= 1
1492                         self.history_pos = hlen-1
1493
1494         def historyBack(self):
1495                 hlen = len(self.history)
1496                 if hlen > 1 and self.history_pos > 0:
1497                         self.history_pos -= 1
1498                         self.setHistoryPath()
1499
1500         def historyNext(self):
1501                 hlen = len(self.history)
1502                 if hlen > 1 and self.history_pos < (hlen-1):
1503                         self.history_pos += 1
1504                         self.setHistoryPath()
1505
1506         def setHistoryPath(self):
1507                 path = self.history[self.history_pos][:]
1508                 ref = path.pop()
1509                 del self.servicePath[:]
1510                 self.servicePath += path
1511                 self.saveRoot()
1512                 root = path[-1]
1513                 cur_root = self.getRoot()
1514                 if cur_root and cur_root != root:
1515                         self.setRoot(root)
1516                 self.session.nav.playService(ref)
1517                 self.setCurrentSelection(ref)
1518                 self.saveChannel(ref)
1519
1520         def saveRoot(self):
1521                 path = ''
1522                 for i in self.servicePath:
1523                         path += i.toString()
1524                         path += ';'
1525                 if path and path != self.lastroot.value:
1526                         self.lastroot.value = path
1527                         self.lastroot.save()
1528
1529         def restoreRoot(self):
1530                 tmp = [x for x in self.lastroot.value.split(';') if x != '']
1531                 current = [x.toString() for x in self.servicePath]
1532                 if tmp != current or self.rootChanged:
1533                         self.clearPath()
1534                         cnt = 0
1535                         for i in tmp:
1536                                 self.servicePath.append(eServiceReference(i))
1537                                 cnt += 1
1538                         if cnt:
1539                                 path = self.servicePath.pop()
1540                                 self.enterPath(path)
1541                         else:
1542                                 self.showFavourites()
1543                                 self.saveRoot()
1544                         self.rootChanged = False
1545
1546         def preEnterPath(self, refstr):
1547                 if self.servicePath and self.servicePath[0] != eServiceReference(refstr):
1548                         pathstr = self.lastroot.value
1549                         if pathstr is not None and pathstr.find(refstr) == 0:
1550                                 self.restoreRoot()
1551                                 lastservice=eServiceReference(self.lastservice.value)
1552                                 if lastservice.valid():
1553                                         self.setCurrentSelection(lastservice)
1554                                 return True
1555                 return False
1556
1557         def saveChannel(self, ref):
1558                 if ref is not None:
1559                         refstr = ref.toString()
1560                 else:
1561                         refstr = ""
1562                 if refstr != self.lastservice.value:
1563                         self.lastservice.value = refstr
1564                         self.lastservice.save()
1565
1566         def setCurrentServicePath(self, path):
1567                 if self.history:
1568                         self.history[self.history_pos] = path
1569                 else:
1570                         self.history.append(path)
1571                 self.setHistoryPath()
1572
1573         def getCurrentServicePath(self):
1574                 if self.history:
1575                         return self.history[self.history_pos]
1576                 return None
1577
1578         def recallPrevService(self):
1579                 hlen = len(self.history)
1580                 if hlen > 1:
1581                         if self.history_pos == hlen-1:
1582                                 tmp = self.history[self.history_pos]
1583                                 self.history[self.history_pos] = self.history[self.history_pos-1]
1584                                 self.history[self.history_pos-1] = tmp
1585                         else:
1586                                 tmp = self.history[self.history_pos+1]
1587                                 self.history[self.history_pos+1] = self.history[self.history_pos]
1588                                 self.history[self.history_pos] = tmp
1589                         self.setHistoryPath()
1590
1591         def cancel(self):
1592                 if self.revertMode is None:
1593                         self.restoreRoot()
1594                         lastservice=eServiceReference(self.lastservice.value)
1595                         if lastservice.valid() and self.getCurrentSelection() != lastservice:
1596                                 self.setCurrentSelection(lastservice)
1597                 elif self.revertMode == MODE_TV:
1598                         self.setModeTv()
1599                 elif self.revertMode == MODE_RADIO:
1600                         self.setModeRadio()
1601                 self.revertMode = None
1602                 self.close(None)
1603
1604 class RadioInfoBar(Screen):
1605         def __init__(self, session):
1606                 Screen.__init__(self, session)
1607                 self["RdsDecoder"] = RdsDecoder(self.session.nav)
1608
1609 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, InfoBarBase):
1610
1611         def __init__(self, session, infobar=None):
1612                 ChannelSelectionBase.__init__(self, session)
1613                 ChannelSelectionEdit.__init__(self)
1614                 ChannelSelectionEPG.__init__(self)
1615                 InfoBarBase.__init__(self)
1616                 if not infobar:
1617                         from InfoBar import InfoBar
1618                         infobar = InfoBar.instance
1619                 self.infobar = infobar
1620
1621                 self.onLayoutFinish.append(self.onCreate)
1622
1623                 self.info = session.instantiateDialog(RadioInfoBar) # our simple infobar
1624
1625                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1626                         {
1627                                 "keyTV": self.cancel,
1628                                 "keyRadio": self.cancel,
1629                                 "cancel": self.cancel,
1630                                 "ok": self.channelSelected,
1631                         })
1632
1633                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1634                         {
1635                                 iPlayableService.evStart: self.__evServiceStart,
1636                                 iPlayableService.evEnd: self.__evServiceEnd
1637                         })
1638
1639 ########## RDS Radiotext / Rass Support BEGIN
1640                 self["RdsDecoder"] = self.info["RdsDecoder"]
1641                 self.infobar.rds_display.hide()
1642                 self.onClose.append(self.__onClose)
1643                 self.onShow.append(self.info.show)
1644                 self.onHide.append(self.info.hide)
1645
1646         def __onClose(self):
1647                 del self.info["RdsDecoder"]
1648                 self.session.deleteDialog(self.info)
1649                 lastservice=eServiceReference(config.tv.lastservice.value)
1650                 self.session.nav.playService(lastservice)
1651
1652 ########## RDS Radiotext / Rass Support END
1653
1654         def cancel(self):
1655                 self.info.hide()
1656                 #set previous tv service
1657                 self.close(True)
1658
1659         def __evServiceStart(self):
1660                 service = self.session.nav.getCurrentService()
1661                 if service:
1662                         info = service.info()
1663                         if info:
1664                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1665                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1666
1667         def __evServiceEnd(self):
1668                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1669
1670         def saveRoot(self):
1671                 path = ''
1672                 for i in self.servicePathRadio:
1673                         path += i.toString()
1674                         path += ';'
1675                 if path and path != config.radio.lastroot.value:
1676                         config.radio.lastroot.value = path
1677                         config.radio.lastroot.save()
1678
1679         def restoreRoot(self):
1680                 tmp = [x for x in config.radio.lastroot.value.split(';') if x != '']
1681                 current = [x.toString() for x in self.servicePathRadio]
1682                 if tmp != current or self.rootChanged:
1683                         self.clearPath()
1684                         cnt = 0
1685                         for i in tmp:
1686                                 self.servicePathRadio.append(eServiceReference(i))
1687                                 cnt += 1
1688                         if cnt:
1689                                 path = self.servicePathRadio.pop()
1690                                 self.enterPath(path)
1691                         else:
1692                                 self.showFavourites()
1693                                 self.saveRoot()
1694                         self.rootChanged = False
1695
1696         def preEnterPath(self, refstr):
1697                 if self.servicePathRadio and self.servicePathRadio[0] != eServiceReference(refstr):
1698                         pathstr = config.radio.lastroot.value
1699                         if pathstr is not None and pathstr.find(refstr) == 0:
1700                                 self.restoreRoot()
1701                                 lastservice=eServiceReference(config.radio.lastservice.value)
1702                                 if lastservice.valid():
1703                                         self.setCurrentSelection(lastservice)
1704                                 return True
1705                 return False
1706
1707         def onCreate(self):
1708                 self.setRadioMode()
1709                 self.restoreRoot()
1710                 lastservice=eServiceReference(config.radio.lastservice.value)
1711                 if lastservice.valid():
1712                         self.servicelist.setCurrent(lastservice)
1713                         self.session.nav.playService(lastservice)
1714                 else:
1715                         self.session.nav.stopService()
1716                 self.info.show()
1717
1718         def channelSelected(self): # just return selected service
1719                 ref = self.getCurrentSelection()
1720                 if self.movemode:
1721                         self.toggleMoveMarked()
1722                 elif (ref.flags & 7) == 7:
1723                         self.enterPath(ref)
1724                 elif self.bouquet_mark_edit != OFF:
1725                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1726                                 self.doMark()
1727                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1728                         cur_root = self.getRoot()
1729                         if not cur_root or not (cur_root.flags & eServiceReference.isGroup):
1730                                 playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1731                                 if playingref is None or playingref != ref:
1732                                         self.session.nav.playService(ref)
1733                                         config.radio.lastservice.value = ref.toString()
1734                                         config.radio.lastservice.save()
1735                                 self.saveRoot()
1736
1737 class SimpleChannelSelection(ChannelSelectionBase):
1738         def __init__(self, session, title):
1739                 ChannelSelectionBase.__init__(self, session)
1740                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1741                         {
1742                                 "cancel": self.close,
1743                                 "ok": self.channelSelected,
1744                                 "keyRadio": self.setModeRadio,
1745                                 "keyTV": self.setModeTv,
1746                         })
1747                 self.title = title
1748                 self.onLayoutFinish.append(self.layoutFinished)
1749
1750         def layoutFinished(self):
1751                 self.setModeTv()
1752
1753         def channelSelected(self): # just return selected service
1754                 ref = self.getCurrentSelection()
1755                 if (ref.flags & 7) == 7:
1756                         self.enterPath(ref)
1757                 elif not (ref.flags & eServiceReference.isMarker):
1758                         ref = self.getCurrentSelection()
1759                         self.close(ref)
1760
1761         def setModeTv(self):
1762                 self.setTvMode()
1763                 self.showFavourites()
1764
1765         def setModeRadio(self):
1766                 self.setRadioMode()
1767                 self.showFavourites()