Do delete userbouquets when they are renamed
[openblackhole/openblackhole-enigma2.git] / lib / python / Screens / ChannelSelection.py
1 from Tools.Profile import profile
2
3 from Screen import Screen
4 import Screens.InfoBar
5 import Components.ParentalControl
6 from Components.Button import Button
7 from Components.ServiceList import ServiceList, refreshServiceList
8 from Components.ActionMap import NumberActionMap, ActionMap, HelpableActionMap
9 from Components.MenuList import MenuList
10 from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
11 from Components.SystemInfo import SystemInfo
12 profile("ChannelSelection.py 1")
13 from EpgSelection import EPGSelection
14 from enigma import eServiceReference, eEPGCache, eServiceCenter, eRCInput, eTimer, eDVBDB, iPlayableService, iServiceInformation, getPrevAsciiCode, eEnv
15 from Components.config import config, configfile, ConfigSubsection, ConfigText
16 from Tools.NumericalTextInput import NumericalTextInput
17 profile("ChannelSelection.py 2")
18 from Components.NimManager import nimmanager
19 profile("ChannelSelection.py 2.1")
20 from Components.Sources.RdsDecoder import RdsDecoder
21 profile("ChannelSelection.py 2.2")
22 from Components.Sources.ServiceEvent import ServiceEvent
23 from Components.Sources.Event import Event
24 profile("ChannelSelection.py 2.3")
25 from Components.Input import Input
26 profile("ChannelSelection.py 3")
27 from Components.ChoiceList import ChoiceList, ChoiceEntryComponent
28 from Components.SystemInfo import SystemInfo
29 from Screens.InputBox import PinInput
30 from Screens.VirtualKeyBoard import VirtualKeyBoard
31 from Screens.MessageBox import MessageBox
32 from Screens.ServiceInfo import ServiceInfo
33 from Screens.Hotkey import InfoBarHotkey, hotkeyActionMap, getHotkeyFunctions
34 profile("ChannelSelection.py 4")
35 from Screens.PictureInPicture import PictureInPicture
36 from Screens.RdsDisplay import RassInteractive
37 from ServiceReference import ServiceReference
38 from Tools.BoundFunction import boundFunction
39 from Tools import Notifications
40 from Tools.Alternatives import CompareWithAlternatives
41 from Tools.Directories import fileExists
42 from Plugins.Plugin import PluginDescriptor
43 from Components.PluginComponent import plugins
44 from Screens.ChoiceBox import ChoiceBox
45 from Screens.EventView import EventViewEPGSelect
46 from os import remove
47 profile("ChannelSelection.py after imports")
48
49 FLAG_SERVICE_NEW_FOUND = 64 #define in lib/dvb/idvb.h as dxNewFound = 64
50
51 class BouquetSelector(Screen):
52         def __init__(self, session, bouquets, selectedFunc, enableWrapAround=True):
53                 Screen.__init__(self, session)
54
55                 self.selectedFunc=selectedFunc
56
57                 self["actions"] = ActionMap(["OkCancelActions"],
58                         {
59                                 "ok": self.okbuttonClick,
60                                 "cancel": self.cancelClick
61                         })
62                 entrys = [ (x[0], x[1]) for x in bouquets ]
63                 self["menu"] = MenuList(entrys, enableWrapAround)
64
65         def getCurrent(self):
66                 cur = self["menu"].getCurrent()
67                 return cur and cur[1]
68
69         def okbuttonClick(self):
70                 self.selectedFunc(self.getCurrent())
71
72         def up(self):
73                 self["menu"].up()
74
75         def down(self):
76                 self["menu"].down()
77
78         def cancelClick(self):
79                 self.close(False)
80
81 class SilentBouquetSelector:
82         def __init__(self, bouquets, enableWrapAround=False, current=0):
83                 self.bouquets = [b[1] for b in bouquets]
84                 self.pos = current
85                 self.count = len(bouquets)
86                 self.enableWrapAround = enableWrapAround
87
88         def up(self):
89                 if self.pos > 0 or self.enableWrapAround:
90                         self.pos = (self.pos - 1) % self.count
91
92         def down(self):
93                 if self.pos < (self.count - 1) or self.enableWrapAround:
94                         self.pos = (self.pos + 1) % self.count
95
96         def getCurrent(self):
97                 return self.bouquets[self.pos]
98
99 # csel.bouquet_mark_edit values
100 OFF = 0
101 EDIT_BOUQUET = 1
102 EDIT_ALTERNATIVES = 2
103
104 def append_when_current_valid(current, menu, args, level=0, key=""):
105         if current and current.valid() and level <= config.usage.setup_level.index:
106                 menu.append(ChoiceEntryComponent(key, args))
107
108 class ChannelContextMenu(Screen):
109         def __init__(self, session, csel):
110
111                 Screen.__init__(self, session)
112                 #raise Exception("we need a better summary screen here")
113                 self.csel = csel
114                 self.bsel = None
115
116                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions", "MenuActions"],
117                         {
118                                 "ok": self.okbuttonClick,
119                                 "cancel": self.cancelClick,
120                                 "blue": self.showServiceInPiP,
121                                 "red": self.playMain,
122                                 "menu": self.openSetup,
123                                 "2": self.renameEntry,
124                                 "3": self.findCurrentlyPlayed,
125                                 "5": self.addServiceToBouquetOrAlternative,
126                                 "6": self.toggleMoveModeSelect,
127                                 "8": self.removeEntry
128                         })
129                 menu = [ ]
130
131                 self.removeFunction = False
132                 self.addFunction = False
133                 current = csel.getCurrentSelection()
134                 current_root = csel.getRoot()
135                 current_sel_path = current.getPath()
136                 current_sel_flags = current.flags
137                 inBouquetRootList = current_root and 'FROM BOUQUET "bouquets.' in current_root.getPath() #FIXME HACK
138                 inAlternativeList = current_root and 'FROM BOUQUET "alternatives' in current_root.getPath()
139                 self.inBouquet = csel.getMutableList() is not None
140                 haveBouquets = config.usage.multibouquet.value
141                 from Components.ParentalControl import parentalControl
142                 self.parentalControl = parentalControl
143                 self.parentalControlEnabled = config.ParentalControl.configured.value and config.ParentalControl.servicepinactive.value
144                 if not (current_sel_path or current_sel_flags & (eServiceReference.isDirectory|eServiceReference.isMarker)):
145                         append_when_current_valid(current, menu, (_("show transponder info"), self.showServiceInformations), level=2)
146                 if csel.bouquet_mark_edit == OFF and not csel.entry_marked:
147                         if not inBouquetRootList:
148                                 isPlayable = not (current_sel_flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
149                                 if isPlayable:
150                                         for p in plugins.getPlugins(PluginDescriptor.WHERE_CHANNEL_CONTEXT_MENU):
151                                                 append_when_current_valid(current, menu, (p.name, boundFunction(self.runPlugin, p)), key="bullet")
152                                         if config.servicelist.startupservice.value == self.csel.getCurrentSelection().toString():
153                                                 append_when_current_valid(current, menu, (_("stop using as startup service"), self.unsetStartupService), level=0)
154                                         else:
155                                                 append_when_current_valid(current, menu, (_("set as startup service"), self.setStartupService), level=0)
156                                         if self.parentalControlEnabled:
157                                                 if self.parentalControl.getProtectionLevel(csel.getCurrentSelection().toCompareString()) == -1:
158                                                         append_when_current_valid(current, menu, (_("add to parental protection"), boundFunction(self.addParentalProtection, csel.getCurrentSelection())), level=0)
159                                                 else:
160                                                         append_when_current_valid(current, menu, (_("remove from parental protection"), boundFunction(self.removeParentalProtection, csel.getCurrentSelection())), level=0)
161                                         if haveBouquets:
162                                                 bouquets = self.csel.getBouquetList()
163                                                 if bouquets is None:
164                                                         bouquetCnt = 0
165                                                 else:
166                                                         bouquetCnt = len(bouquets)
167                                                 if not self.inBouquet or bouquetCnt > 1:
168                                                         append_when_current_valid(current, menu, (_("add service to bouquet"), self.addServiceToBouquetSelected), level=0, key="5")
169                                                         self.addFunction = self.addServiceToBouquetSelected
170                                                 if not self.inBouquet:
171                                                         append_when_current_valid(current, menu, (_("remove entry"), self.removeEntry), level = 0, key="8")
172                                                         self.removeFunction = self.removeSatelliteService
173                                         else:
174                                                 if not self.inBouquet:
175                                                         append_when_current_valid(current, menu, (_("add service to favourites"), self.addServiceToBouquetSelected), level=0, key="5")
176                                                         self.addFunction = self.addServiceToBouquetSelected
177                                         if SystemInfo["PIPAvailable"]:
178                                                 if not self.parentalControlEnabled or self.parentalControl.getProtectionLevel(csel.getCurrentSelection().toCompareString()) == -1:
179                                                         if self.csel.dopipzap:
180                                                                 append_when_current_valid(current, menu, (_("play in mainwindow"), self.playMain), level=0, key="red")
181                                                         else:   
182                                                                 append_when_current_valid(current, menu, (_("play as picture in picture"), self.showServiceInPiP), level=0, key="blue")
183                                         append_when_current_valid(current, menu, (_("find currently played service"), self.findCurrentlyPlayed), level=0, key="3")
184                                 else:
185                                         if 'FROM SATELLITES' in current_root.getPath() and current and _("Services") in eServiceCenter.getInstance().info(current).getName(current):
186                                                 unsigned_orbpos = current.getUnsignedData(4) >> 16
187                                                 if unsigned_orbpos == 0xFFFF:
188                                                         append_when_current_valid(current, menu, (_("remove cable services"), self.removeSatelliteServices), level = 0)
189                                                 elif unsigned_orbpos == 0xEEEE:
190                                                         append_when_current_valid(current, menu, (_("remove terrestrial services"), self.removeSatelliteServices), level = 0)
191                                                 else:
192                                                         append_when_current_valid(current, menu, (_("remove selected satellite"), self.removeSatelliteServices), level = 0)
193                                         if haveBouquets:
194                                                 if not self.inBouquet and not "PROVIDERS" in current_sel_path:
195                                                         append_when_current_valid(current, menu, (_("copy to bouquets"), self.copyCurrentToBouquetList), level=0)
196                                         if ("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) in current_sel_path:
197                                                 append_when_current_valid(current, menu, (_("remove all new found flags"), self.removeAllNewFoundFlags), level=0)
198                                 if self.inBouquet:
199                                         append_when_current_valid(current, menu, (_("rename entry"), self.renameEntry), level=0, key="2")
200                                         if not inAlternativeList:
201                                                 append_when_current_valid(current, menu, (_("remove entry"), self.removeEntry), level=0, key="8")
202                                                 self.removeFunction = self.removeCurrentService
203                                 if current_root and ("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) in current_root.getPath():
204                                         append_when_current_valid(current, menu, (_("remove new found flag"), self.removeNewFoundFlag), level=0)
205                         else:
206                                         if self.parentalControlEnabled:
207                                                 if self.parentalControl.getProtectionLevel(csel.getCurrentSelection().toCompareString()) == -1:
208                                                         append_when_current_valid(current, menu, (_("add bouquet to parental protection"), boundFunction(self.addParentalProtection, csel.getCurrentSelection())), level=0)
209                                                 else:
210                                                         append_when_current_valid(current, menu, (_("remove bouquet from parental protection"), boundFunction(self.removeParentalProtection, csel.getCurrentSelection())), level=0)
211                                         menu.append(ChoiceEntryComponent(text=(_("add bouquet"), self.showBouquetInputBox)))
212                                         append_when_current_valid(current, menu, (_("rename entry"), self.renameEntry), level=0, key="2")
213                                         append_when_current_valid(current, menu, (_("remove entry"), self.removeEntry), level=0, key="8")
214                                         self.removeFunction = self.removeBouquet
215                 if self.inBouquet: # current list is editable?
216                         if csel.bouquet_mark_edit == OFF:
217                                 if csel.movemode:
218                                         append_when_current_valid(current, menu, (_("disable move mode"), self.toggleMoveMode), level=0, key="6")
219                                 else:
220                                         append_when_current_valid(current, menu, (_("enable move mode"), self.toggleMoveMode), level=1, key="6")
221                                 if not csel.entry_marked and not inBouquetRootList and current_root and not (current_root.flags & eServiceReference.isGroup):
222                                         if current.type != -1:
223                                                 menu.append(ChoiceEntryComponent(text=(_("add marker"), self.showMarkerInputBox)))
224                                         if not csel.movemode:
225                                                 if haveBouquets:
226                                                         append_when_current_valid(current, menu, (_("enable bouquet edit"), self.bouquetMarkStart), level=0)
227                                                 else:
228                                                         append_when_current_valid(current, menu, (_("enable favourite edit"), self.bouquetMarkStart), level=0)
229                                         if current_sel_flags & eServiceReference.isGroup:
230                                                 append_when_current_valid(current, menu, (_("edit alternatives"), self.editAlternativeServices), level=2)
231                                                 append_when_current_valid(current, menu, (_("show alternatives"), self.showAlternativeServices), level=2)
232                                                 append_when_current_valid(current, menu, (_("remove all alternatives"), self.removeAlternativeServices), level=2)
233                                         elif not current_sel_flags & eServiceReference.isMarker:
234                                                 append_when_current_valid(current, menu, (_("add alternatives"), self.addAlternativeServices), level=2)
235                         else:
236                                 if csel.bouquet_mark_edit == EDIT_BOUQUET:
237                                         if haveBouquets:
238                                                 append_when_current_valid(current, menu, (_("end bouquet edit"), self.bouquetMarkEnd), level=0)
239                                                 append_when_current_valid(current, menu, (_("abort bouquet edit"), self.bouquetMarkAbort), level=0)
240                                         else:
241                                                 append_when_current_valid(current, menu, (_("end favourites edit"), self.bouquetMarkEnd), level=0)
242                                                 append_when_current_valid(current, menu, (_("abort favourites edit"), self.bouquetMarkAbort), level=0)
243                                         if current_sel_flags & eServiceReference.isMarker:
244                                                 append_when_current_valid(current, menu, (_("rename entry"), self.renameEntry), level=0, key="2")
245                                                 append_when_current_valid(current, menu, (_("remove entry"), self.removeEntry), level=0, key="8")
246                                                 self.removeFunction = self.removeCurrentService
247                                 else:
248                                         append_when_current_valid(current, menu, (_("end alternatives edit"), self.bouquetMarkEnd), level=0)
249                                         append_when_current_valid(current, menu, (_("abort alternatives edit"), self.bouquetMarkAbort), level=0)
250
251                 menu.append(ChoiceEntryComponent("menu", (_("Configuration..."), self.openSetup)))
252                 self["menu"] = ChoiceList(menu)
253
254         def addServiceToBouquetOrAlternative(self):
255                 if self.addFunction:
256                         self.addFunction()
257                 else:
258                         return 0
259
260         def removeEntry(self):
261                 if self.removeFunction and self.csel.servicelist.getCurrent() and self.csel.servicelist.getCurrent().valid():
262                         if self.csel.confirmRemove:
263                                 list = [(_("yes"), True), (_("no"), False), (_("yes") + " " + _("and never ask again this session again"), "never")]
264                                 self.session.openWithCallback(self.removeFunction, MessageBox, _("Are you sure to remove this entry?"), list=list)
265                         else:
266                                 self.removeFunction(True)
267                 else:
268                         return 0
269
270         def removeCurrentService(self, answer):
271                 if answer:
272                         if answer == "never":
273                                 self.csel.confirmRemove = False
274                         self.csel.removeCurrentService()
275                         self.close()
276
277         def removeSatelliteService(self, answer):
278                 if answer:
279                         if answer == "never":
280                                 self.csel.confirmRemove = False
281                         self.csel.removeSatelliteService()
282                         self.close()
283
284         def removeBouquet(self, answer):
285                 if answer:
286                         self.csel.removeBouquet()
287                         eDVBDB.getInstance().reloadBouquets()
288                         self.close()
289
290         def playMain(self):
291                 sel = self.csel.getCurrentSelection()
292                 if sel and sel.valid() and self.csel.dopipzap and (not self.parentalControlEnabled or self.parentalControl.getProtectionLevel(self.csel.getCurrentSelection().toCompareString()) == -1):
293                         self.csel.zap()
294                         self.csel.setCurrentSelection(sel)
295                         self.close(True)
296                 else:
297                         return 0
298
299         def okbuttonClick(self):
300                 self["menu"].getCurrent()[0][1]()
301
302         def openSetup(self):
303                 from Screens.Setup import Setup
304                 self.session.openWithCallback(self.cancelClick, Setup, "userinterface")
305
306         def cancelClick(self, dummy=False):
307                 self.close(False)
308
309         def showServiceInformations(self):
310                 self.session.open( ServiceInfo, self.csel.getCurrentSelection() )
311
312         def setStartupService(self):
313                 config.servicelist.startupservice.value = self.csel.getCurrentSelection().toString()
314                 path = ';'.join([i.toString() for i in self.csel.servicePath])
315                 config.servicelist.startuproot.value = path
316                 config.servicelist.startupmode.value = config.servicelist.lastmode.value
317                 config.servicelist.save()
318                 configfile.save()
319                 self.close()
320
321         def unsetStartupService(self):
322                 config.servicelist.startupservice.value = ''
323                 config.servicelist.save()
324                 configfile.save()
325                 self.close()
326
327         def showBouquetInputBox(self):
328                 self.session.openWithCallback(self.bouquetInputCallback, VirtualKeyBoard, title=_("Please enter a name for the new bouquet"), text="bouquetname", maxSize=False, visible_width=56, type=Input.TEXT)
329
330         def bouquetInputCallback(self, bouquet):
331                 if bouquet is not None:
332                         self.csel.addBouquet(bouquet, None)
333                 self.close()
334
335         def addParentalProtection(self, service):
336                 self.parentalControl.protectService(service.toCompareString())
337                 self.close()
338
339         def removeParentalProtection(self, service):
340                 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"))
341
342         def pinEntered(self, service, result):
343                 if result:
344                         self.parentalControl.unProtectService(service)
345                         self.close()
346                 else:
347                         self.session.openWithCallback(self.close, MessageBox, _("The pin code you entered is wrong."), MessageBox.TYPE_ERROR)
348
349         def showServiceInPiP(self):
350                 if self.csel.dopipzap or (self.parentalControlEnabled and not self.parentalControl.getProtectionLevel(self.csel.getCurrentSelection().toCompareString()) == -1):
351                         return 0
352                 if self.session.pipshown:
353                         del self.session.pip
354                 self.session.pip = self.session.instantiateDialog(PictureInPicture)
355                 self.session.pip.show()
356                 newservice = self.csel.servicelist.getCurrent()
357                 currentBouquet = self.csel.servicelist and self.csel.servicelist.getRoot()
358                 if newservice and newservice.valid():
359                         if self.session.pip.playService(newservice):
360                                 self.session.pipshown = True
361                                 self.session.pip.servicePath = self.csel.getCurrentServicePath()
362                                 self.session.pip.servicePath[1] = currentBouquet
363                                 self.close(True)
364                         else:
365                                 self.session.pipshown = False
366                                 del self.session.pip
367                                 self.session.openWithCallback(self.close, MessageBox, _("Could not open Picture in Picture"), MessageBox.TYPE_ERROR)
368                 else:
369                         return 0
370
371         def addServiceToBouquetSelected(self):
372                 bouquets = self.csel.getBouquetList()
373                 if bouquets is None:
374                         cnt = 0
375                 else:
376                         cnt = len(bouquets)
377                 if cnt > 1: # show bouquet list
378                         self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, bouquets, self.addCurrentServiceToBouquet)
379                 elif cnt == 1: # add to only one existing bouquet
380                         self.addCurrentServiceToBouquet(bouquets[0][1], closeBouquetSelection=False)
381
382         def bouquetSelClosed(self, recursive):
383                 self.bsel = None
384                 if recursive:
385                         self.close(False)
386
387         def removeSatelliteServices(self):
388                 self.csel.removeSatelliteServices()
389                 self.close()
390
391         def copyCurrentToBouquetList(self):
392                 self.csel.copyCurrentToBouquetList()
393                 self.close()
394
395         def showMarkerInputBox(self):
396                 self.session.openWithCallback(self.markerInputCallback, VirtualKeyBoard, title=_("Please enter a name for the new marker"), text="markername", maxSize=False, visible_width=56, type=Input.TEXT)
397
398         def markerInputCallback(self, marker):
399                 if marker is not None:
400                         self.csel.addMarker(marker)
401                 self.close()
402
403         def addCurrentServiceToBouquet(self, dest, closeBouquetSelection=True):
404                 self.csel.addServiceToBouquet(dest)
405                 if self.bsel is not None:
406                         self.bsel.close(True)
407                 else:
408                         self.close(closeBouquetSelection) # close bouquet selection
409
410         def renameEntry(self):
411                 if self.inBouquet and self.csel.servicelist.getCurrent() and self.csel.servicelist.getCurrent().valid() and not self.csel.entry_marked:
412                         self.csel.renameEntry()
413                         self.close()
414                 else:
415                         return 0
416
417         def toggleMoveMode(self):
418                 if self.inBouquet and self.csel.servicelist.getCurrent() and self.csel.servicelist.getCurrent().valid():
419                         self.csel.toggleMoveMode()
420                         self.close()
421                 else:
422                         return 0
423
424         def toggleMoveModeSelect(self):
425                 if self.inBouquet and self.csel.servicelist.getCurrent() and self.csel.servicelist.getCurrent().valid():
426                         self.csel.toggleMoveMode(True)
427                         self.close()
428                 else:
429                         return 0
430
431         def bouquetMarkStart(self):
432                 self.csel.startMarkedEdit(EDIT_BOUQUET)
433                 self.close()
434
435         def bouquetMarkEnd(self):
436                 self.csel.endMarkedEdit(abort=False)
437                 self.close()
438
439         def bouquetMarkAbort(self):
440                 self.csel.endMarkedEdit(abort=True)
441                 self.close()
442
443         def removeNewFoundFlag(self):
444                 eDVBDB.getInstance().removeFlag(self.csel.getCurrentSelection(), FLAG_SERVICE_NEW_FOUND)
445                 self.close()
446
447         def removeAllNewFoundFlags(self):
448                 curpath = self.csel.getCurrentSelection().getPath()
449                 idx = curpath.find("satellitePosition == ")
450                 if idx != -1:
451                         tmp = curpath[idx+21:]
452                         idx = tmp.find(')')
453                         if idx != -1:
454                                 satpos = int(tmp[:idx])
455                                 eDVBDB.getInstance().removeFlags(FLAG_SERVICE_NEW_FOUND, -1, -1, -1, satpos)
456                 self.close()
457
458         def editAlternativeServices(self):
459                 self.csel.startMarkedEdit(EDIT_ALTERNATIVES)
460                 self.close()
461
462         def showAlternativeServices(self):
463                 self.csel["Service"].editmode = True
464                 self.csel.enterPath(self.csel.getCurrentSelection())
465                 self.close()
466
467         def removeAlternativeServices(self):
468                 self.csel.removeAlternativeServices()
469                 self.close()
470
471         def addAlternativeServices(self):
472                 self.csel.addAlternativeServices()
473                 self.csel.startMarkedEdit(EDIT_ALTERNATIVES)
474                 self.close()
475
476         def findCurrentlyPlayed(self):
477                 sel = self.csel.getCurrentSelection()
478                 if sel and sel.valid() and not self.csel.entry_marked:
479                         currentPlayingService = (hasattr(self.csel, "dopipzap") and self.csel.dopipzap) and self.session.pip.getCurrentService() or self.session.nav.getCurrentlyPlayingServiceOrGroup()
480                         self.csel.servicelist.setCurrent(currentPlayingService, adjust=False)
481                         if self.csel.getCurrentSelection() != currentPlayingService:
482                                 self.csel.setCurrentSelection(sel)
483                         self.close()
484                 else:
485                         return 0
486
487         def runPlugin(self, plugin):
488                 plugin(session=self.session, service=self.csel.getCurrentSelection())
489                 self.close()
490
491 class SelectionEventInfo:
492         def __init__(self):
493                 self["Service"] = self["ServiceEvent"] = ServiceEvent()
494                 self["Event"] = Event()
495                 self.servicelist.connectSelChanged(self.__selectionChanged)
496                 self.timer = eTimer()
497                 self.timer.callback.append(self.updateEventInfo)
498                 self.onShown.append(self.__selectionChanged)
499
500         def __selectionChanged(self):
501                 if self.execing:
502                         self.timer.start(100, True)
503
504         def updateEventInfo(self):
505                 cur = self.getCurrentSelection()
506                 service = self["Service"]
507                 service.newService(cur)
508                 self["Event"].newEvent(service.event)
509
510 class ChannelSelectionEPG(InfoBarHotkey):
511         def __init__(self):
512                 self.hotkeys = [("Info (EPG)", "info", "Infobar/openEventView"),
513                         ("Info (EPG)" + " " + _("long"), "info_long", "Infobar/showEventInfoPlugins"),
514                         ("Epg/Guide", "epg", "Plugins/Extensions/GraphMultiEPG/1"),
515                         ("Epg/Guide" + " " + _("long"), "epg_long", "Infobar/showEventInfoPlugins")]
516                 self["ChannelSelectEPGActions"] = hotkeyActionMap(["ChannelSelectEPGActions"], dict((x[1], self.hotkeyGlobal) for x in self.hotkeys))
517                 self.eventViewEPG = self.start_bouquet = self.epg_bouquet = None
518                 self.currentSavedPath = []
519                 self.onExecBegin.append(self.clearLongkeyPressed)
520
521         def getKeyFunctions(self, key):
522                 selection = eval("config.misc.hotkey." + key + ".value.split(',')")
523                 selected = []
524                 for x in selection:
525                         function = list(function for function in getHotkeyFunctions() if function[1] == x and function[2] == "EPG")
526                         if function:
527                                 selected.append(function[0])
528                 return selected
529
530         def runPlugin(self, plugin):
531                 Screens.InfoBar.InfoBar.instance.runPlugin(plugin)
532
533         def getEPGPluginList(self, getAll=False):
534                 pluginlist = [(p.name, boundFunction(self.runPlugin, p), p.path) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EVENTINFO) \
535                                 if 'selectedevent' not in p.__call__.func_code.co_varnames] or []
536                 from Components.ServiceEventTracker import InfoBarCount
537                 if getAll or InfoBarCount == 1:
538                         pluginlist.append((_("Show EPG for current channel..."), self.openSingleServiceEPG, "current_channel"))
539                 pluginlist.append((_("Multi EPG"), self.openMultiServiceEPG, "multi_epg"))
540                 pluginlist.append((_("Current event EPG"), self.openEventView, "event_epg"))
541                 return pluginlist
542
543         def showEventInfoPlugins(self):
544                 pluginlist = self.getEPGPluginList()
545                 if pluginlist:
546                         self.session.openWithCallback(self.EventInfoPluginChosen, ChoiceBox, title=_("Please choose an extension..."), list = pluginlist, skin_name = "EPGExtensionsList")
547                 else:
548                         self.openSingleServiceEPG()
549
550         def EventInfoPluginChosen(self, answer):
551                 if answer is not None:
552                         answer[1]()
553
554         def openEventView(self):
555                 epglist = [ ]
556                 self.epglist = epglist
557                 ref = self.getCurrentSelection()
558                 epg = eEPGCache.getInstance()
559                 now_event = epg.lookupEventTime(ref, -1, 0)
560                 if now_event:
561                         epglist.append(now_event)
562                         next_event = epg.lookupEventTime(ref, -1, 1)
563                         if next_event:
564                                 epglist.append(next_event)
565                 if epglist:
566                         self.eventViewEPG = self.session.openWithCallback(self.eventViewEPGClosed, EventViewEPGSelect, epglist[0], ServiceReference(ref), self.eventViewEPGCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
567
568         def eventViewEPGCallback(self, setEvent, setService, val):
569                 epglist = self.epglist
570                 if len(epglist) > 1:
571                         tmp = epglist[0]
572                         epglist[0] = epglist[1]
573                         epglist[1] = tmp
574                         setEvent(epglist[0])
575
576         def eventViewEPGClosed(self, ret=False):
577                 self.eventViewEPG = None
578                 if ret:
579                         self.close()
580
581         def openMultiServiceEPG(self):
582                 ref = self.getCurrentSelection()
583                 if ref:
584                         self.start_bouquet = self.epg_bouquet = self.servicelist.getRoot()
585                         self.savedService = ref
586                         self.currentSavedPath = self.servicePath[:]
587                         services = self.getServicesList(self.servicelist.getRoot())
588                         self.session.openWithCallback(self.SingleMultiEPGClosed, EPGSelection, services, self.zapToService, None, bouquetChangeCB=self.changeBouquetForMultiEPG)
589
590         def openSingleServiceEPG(self):
591                 ref = self.getCurrentSelection()
592                 if ref:
593                         self.start_bouquet = self.epg_bouquet = self.servicelist.getRoot()
594                         self.savedService = ref
595                         self.currentSavedPath = self.servicePath[:]
596                         self.session.openWithCallback(self.SingleMultiEPGClosed, EPGSelection, ref, self.zapToService, serviceChangeCB=self.changeServiceCB, bouquetChangeCB=self.changeBouquetForSingleEPG)
597
598         def openSimilarList(self, eventid, refstr):
599                 self.session.open(EPGSelection, refstr, None, eventid)
600
601         def getServicesList(self, root):
602                 services = [ ]
603                 servicelist = root and eServiceCenter.getInstance().list(root)
604                 if not servicelist is None:
605                         while True:
606                                 service = servicelist.getNext()
607                                 if not service.valid():
608                                         break
609                                 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker):
610                                         continue
611                                 services.append(ServiceReference(service))
612                 return services
613
614         def SingleMultiEPGClosed(self, ret=False):
615                 if ret:
616                         service = self.getCurrentSelection()
617                         if self.eventViewEPG:
618                                 self.eventViewEPG.close(service)
619                         elif service is not None:
620                                 self.close()
621                 else:
622                         if self.start_bouquet != self.epg_bouquet and len(self.currentSavedPath) > 0:
623                                 self.clearPath()
624                                 self.enterPath(self.bouquet_root)
625                                 self.epg_bouquet = self.start_bouquet
626                                 self.enterPath(self.epg_bouquet)
627                         self.setCurrentSelection(self.savedService)
628
629         def changeBouquetForSingleEPG(self, direction, epg):
630                 if config.usage.multibouquet.value:
631                         inBouquet = self.getMutableList() is not None
632                         if inBouquet and len(self.servicePath) > 1:
633                                 self.pathUp()
634                                 if direction < 0:
635                                         self.moveUp()
636                                 else:
637                                         self.moveDown()
638                                 cur = self.getCurrentSelection()
639                                 self.enterPath(cur)
640                                 self.epg_bouquet = self.servicelist.getRoot()
641                                 epg.setService(ServiceReference(self.getCurrentSelection()))
642
643         def changeBouquetForMultiEPG(self, direction, epg):
644                 if config.usage.multibouquet.value:
645                         inBouquet = self.getMutableList() is not None
646                         if inBouquet and len(self.servicePath) > 1:
647                                 self.pathUp()
648                                 if direction < 0:
649                                         self.moveUp()
650                                 else:
651                                         self.moveDown()
652                                 cur = self.getCurrentSelection()
653                                 self.enterPath(cur)
654                                 self.epg_bouquet = self.servicelist.getRoot()
655                                 services = self.getServicesList(self.epg_bouquet)
656                                 epg.setServices(services)
657
658         def changeServiceCB(self, direction, epg):
659                 beg = self.getCurrentSelection()
660                 while True:
661                         if direction > 0:
662                                 self.moveDown()
663                         else:
664                                 self.moveUp()
665                         cur = self.getCurrentSelection()
666                         if cur == beg or not (cur.flags & eServiceReference.isMarker):
667                                 break
668                 epg.setService(ServiceReference(self.getCurrentSelection()))
669
670         def zapToService(self, service, preview=False, zapback=False):
671                 if self.startServiceRef is None:
672                         self.startServiceRef = self.session.nav.getCurrentlyPlayingServiceOrGroup()
673                 if service is not None:
674                         if self.servicelist.getRoot() != self.epg_bouquet:
675                                 self.servicelist.clearPath()
676                                 if self.servicelist.bouquet_root != self.epg_bouquet:
677                                         self.servicelist.enterPath(self.servicelist.bouquet_root)
678                                 self.servicelist.enterPath(self.epg_bouquet)
679                         self.servicelist.setCurrent(service)
680                 if not zapback or preview:
681                         self.zap(enable_pipzap=True)
682                 if (self.dopipzap or zapback) and not preview:
683                         self.zapBack()
684                 if not preview:
685                         self.startServiceRef = None
686                         self.startRoot = None
687                         self.revertMode = None
688
689 class ChannelSelectionEdit:
690         def __init__(self):
691                 self.entry_marked = False
692                 self.bouquet_mark_edit = OFF
693                 self.mutableList = None
694                 self.__marked = [ ]
695                 self.saved_title = None
696                 self.saved_root = None
697                 self.current_ref = None
698                 self.editMode = False
699                 self.confirmRemove = True
700
701                 class ChannelSelectionEditActionMap(ActionMap):
702                         def __init__(self, csel, contexts=[ ], actions={ }, prio=0):
703                                 ActionMap.__init__(self, contexts, actions, prio)
704                                 self.csel = csel
705
706                         def action(self, contexts, action):
707                                 if action == "cancel":
708                                         self.csel.handleEditCancel()
709                                         return 0 # fall-trough
710                                 elif action == "ok":
711                                         return 0 # fall-trough
712                                 else:
713                                         return ActionMap.action(self, contexts, action)
714
715                 self["ChannelSelectEditActions"] = ChannelSelectionEditActionMap(self, ["ChannelSelectEditActions", "OkCancelActions"],
716                         {
717                                 "contextMenu": self.doContext,
718                         })
719
720         def getMutableList(self, root=eServiceReference()):
721                 if not self.mutableList is None:
722                         return self.mutableList
723                 serviceHandler = eServiceCenter.getInstance()
724                 if not root.valid():
725                         root=self.getRoot()
726                 list = root and serviceHandler.list(root)
727                 if list is not None:
728                         return list.startEdit()
729                 return None
730
731         def buildBouquetID(self, str):
732                 tmp = str.lower()
733                 name = ''
734                 for c in tmp:
735                         if (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9'):
736                                 name += c
737                         else:
738                                 name += '_'
739                 return name
740
741         def renameEntry(self):
742                 self.editMode = True
743                 cur = self.getCurrentSelection()
744                 if cur and cur.valid():
745                         name = eServiceCenter.getInstance().info(cur).getName(cur) or ServiceReference(cur).getServiceName() or ""
746                         name.replace('\xc2\x86', '').replace('\xc2\x87', '')
747                         if name:
748                                 self.session.openWithCallback(self.renameEntryCallback, VirtualKeyBoard, title=_("Please enter new name:"), text=name)
749                 else:
750                         return 0
751
752         def renameEntryCallback(self, name):
753                 if name:
754                         mutableList = self.getMutableList()
755                         if mutableList:
756                                 current = self.servicelist.getCurrent()
757                                 current.setName(name)
758                                 index = self.servicelist.getCurrentIndex()
759                                 mutableList.removeService(current, False)
760                                 mutableList.addService(current)
761                                 mutableList.moveService(current, index)
762                                 mutableList.flushChanges()
763                                 self.servicelist.addService(current, True)
764                                 self.servicelist.removeCurrent()
765                                 if not self.servicelist.atEnd():
766                                         self.servicelist.moveUp()
767
768         def addMarker(self, name):
769                 current = self.servicelist.getCurrent()
770                 mutableList = self.getMutableList()
771                 cnt = 0
772                 while mutableList:
773                         str = '1:64:%d:0:0:0:0:0:0:0::%s'%(cnt, name)
774                         ref = eServiceReference(str)
775                         if current and current.valid():
776                                 if not mutableList.addService(ref, current):
777                                         self.servicelist.addService(ref, True)
778                                         mutableList.flushChanges()
779                                         break
780                         elif not mutableList.addService(ref):
781                                 self.servicelist.addService(ref, True)
782                                 mutableList.flushChanges()
783                                 break
784                         cnt+=1
785
786         def addAlternativeServices(self):
787                 cur_service = ServiceReference(self.getCurrentSelection())
788                 root = self.getRoot()
789                 cur_root = root and ServiceReference(root)
790                 mutableBouquet = cur_root.list().startEdit()
791                 if mutableBouquet:
792                         name = cur_service.getServiceName()
793                         print "NAME", name
794                         if self.mode == MODE_TV:
795                                 str = '1:134:1:0:0:0:0:0:0:0:FROM BOUQUET \"alternatives.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(name))
796                         else:
797                                 str = '1:134:2:0:0:0:0:0:0:0:FROM BOUQUET \"alternatives.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(name))
798                         new_ref = ServiceReference(str)
799                         if not mutableBouquet.addService(new_ref.ref, cur_service.ref):
800                                 mutableBouquet.removeService(cur_service.ref)
801                                 mutableBouquet.flushChanges()
802                                 eDVBDB.getInstance().reloadBouquets()
803                                 mutableAlternatives = new_ref.list().startEdit()
804                                 if mutableAlternatives:
805                                         mutableAlternatives.setListName(name)
806                                         if mutableAlternatives.addService(cur_service.ref):
807                                                 print "add", cur_service.ref.toString(), "to new alternatives failed"
808                                         mutableAlternatives.flushChanges()
809                                         self.servicelist.addService(new_ref.ref, True)
810                                         self.servicelist.removeCurrent()
811                                         if not self.atEnd():
812                                                 self.servicelist.moveUp()
813                                         if cur_service.ref.toString() == self.lastservice.value:
814                                                 self.saveChannel(new_ref.ref)
815                                         if self.startServiceRef and cur_service.ref == self.startServiceRef:
816                                                 self.startServiceRef = new_ref.ref
817                                 else:
818                                         print "get mutable list for new created alternatives failed"
819                         else:
820                                 print "add", str, "to", cur_root.getServiceName(), "failed"
821                 else:
822                         print "bouquetlist is not editable"
823
824         def addBouquet(self, bName, services):
825                 serviceHandler = eServiceCenter.getInstance()
826                 mutableBouquetList = serviceHandler.list(self.bouquet_root).startEdit()
827                 if mutableBouquetList:
828                         if self.mode == MODE_TV:
829                                 bName += _(" (TV)")
830                                 str = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(bName))
831                         else:
832                                 bName += _(" (Radio)")
833                                 str = '1:7:2:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(bName))
834                         new_bouquet_ref = eServiceReference(str)
835                         if not mutableBouquetList.addService(new_bouquet_ref):
836                                 mutableBouquetList.flushChanges()
837                                 eDVBDB.getInstance().reloadBouquets()
838                                 mutableBouquet = serviceHandler.list(new_bouquet_ref).startEdit()
839                                 if mutableBouquet:
840                                         mutableBouquet.setListName(bName)
841                                         if services is not None:
842                                                 for service in services:
843                                                         if mutableBouquet.addService(service):
844                                                                 print "add", service.toString(), "to new bouquet failed"
845                                         mutableBouquet.flushChanges()
846                                 else:
847                                         print "get mutable list for new created bouquet failed"
848                                 # do some voodoo to check if current_root is equal to bouquet_root
849                                 cur_root = self.getRoot();
850                                 str1 = cur_root and cur_root.toString()
851                                 pos1 = str1 and str1.find("FROM BOUQUET") or -1
852                                 pos2 = self.bouquet_rootstr.find("FROM BOUQUET")
853                                 if pos1 != -1 and pos2 != -1 and str1[pos1:] == self.bouquet_rootstr[pos2:]:
854                                         self.servicelist.addService(new_bouquet_ref)
855                                         self.servicelist.resetRoot()
856                         else:
857                                 print "add", str, "to bouquets failed"
858                 else:
859                         print "bouquetlist is not editable"
860
861         def copyCurrentToBouquetList(self):
862                 provider = ServiceReference(self.getCurrentSelection())
863                 providerName = provider.getServiceName()
864                 serviceHandler = eServiceCenter.getInstance()
865                 services = serviceHandler.list(provider.ref)
866                 self.addBouquet(providerName, services and services.getContent('R', True))
867
868         def removeAlternativeServices(self):
869                 cur_service = ServiceReference(self.getCurrentSelection())
870                 end = self.atEnd()
871                 root = self.getRoot()
872                 cur_root = root and ServiceReference(root)
873                 list = cur_service.list()
874                 first_in_alternative = list and list.getNext()
875                 if first_in_alternative:
876                         edit_root = cur_root and cur_root.list().startEdit()
877                         if edit_root:
878                                 if not edit_root.addService(first_in_alternative, cur_service.ref):
879                                         self.servicelist.addService(first_in_alternative, True)
880                                         if cur_service.ref.toString() == self.lastservice.value:
881                                                 self.saveChannel(first_in_alternative)
882                                         if self.startServiceRef and cur_service.ref == self.startServiceRef:
883                                                 self.startServiceRef = first_in_alternative
884                                 else:
885                                         print "couldn't add first alternative service to current root"
886                         else:
887                                 print "couldn't edit current root!!"
888                 else:
889                         print "remove empty alternative list !!"
890                 self.removeBouquet()
891                 if not end:
892                         self.servicelist.moveUp()
893
894         def removeBouquet(self):
895                 refstr = self.getCurrentSelection().toString()
896                 print "removeBouquet", refstr
897                 pos = refstr.find('FROM BOUQUET "')
898                 filename = None
899                 if pos != -1:
900                         refstr = refstr[pos+14:]
901                         pos = refstr.find('"')
902                         if pos != -1:
903                                 filename = eEnv.resolve('${sysconfdir}/enigma2/') + refstr[:pos]
904                 self.removeCurrentService(bouquet=True)
905                 try:
906                         if filename is not None:
907                                 remove(filename)
908                 except OSError:
909                         print "error during remove of", filename
910
911         def removeSatelliteService(self):
912                 current = self.getCurrentSelection()
913                 eDVBDB.getInstance().removeService(current)
914                 refreshServiceList()
915                 if not self.atEnd():
916                         self.servicelist.moveUp()
917
918         def removeSatelliteServices(self):
919                 current = self.getCurrentSelection()
920                 unsigned_orbpos = current.getUnsignedData(4) >> 16
921                 if unsigned_orbpos == 0xFFFF:
922                         messageText = _("Are you sure to remove all cable services?")
923                 elif unsigned_orbpos == 0xEEEE:
924                         messageText = _("Are you sure to remove all terrestrial services?")
925                 else:
926                         if unsigned_orbpos > 1800:
927                                 unsigned_orbpos = 3600 - unsigned_orbpos
928                                 direction = _("W")
929                         else:
930                                 direction = _("E")
931                         messageText = _("Are you sure to remove all %d.%d%s%s services?") % (unsigned_orbpos/10, unsigned_orbpos%10, "\xc2\xb0", direction)
932                 self.session.openWithCallback(self.removeSatelliteServicesCallback, MessageBox, messageText)
933
934         def removeSatelliteServicesCallback(self, answer):
935                 if answer:
936                         currentIndex = self.servicelist.getCurrentIndex()
937                         current = self.getCurrentSelection()
938                         unsigned_orbpos = current.getUnsignedData(4) >> 16
939                         if unsigned_orbpos == 0xFFFF:
940                                 eDVBDB.getInstance().removeServices(int("0xFFFF0000", 16) - 0x100000000)
941                         elif unsigned_orbpos == 0xEEEE:
942                                 eDVBDB.getInstance().removeServices(int("0xEEEE0000", 16) - 0x100000000)
943                         else:
944                                 curpath = current.getPath()
945                                 idx = curpath.find("satellitePosition == ")
946                                 if idx != -1:
947                                         tmp = curpath[idx + 21:]
948                                         idx = tmp.find(')')
949                                         if idx != -1:
950                                                 satpos = int(tmp[:idx])
951                                                 eDVBDB.getInstance().removeServices(-1, -1, -1, satpos)
952                         refreshServiceList()
953                         if hasattr(self, 'showSatellites'):
954                                 self.showSatellites()
955                                 self.servicelist.moveToIndex(currentIndex)
956                                 if currentIndex != self.servicelist.getCurrentIndex():
957                                         self.servicelist.instance.moveSelection(self.servicelist.instance.moveEnd)
958
959 #  multiple marked entry stuff ( edit mode, later multiepg selection )
960         def startMarkedEdit(self, type):
961                 self.savedPath = self.servicePath[:]
962                 if type == EDIT_ALTERNATIVES:
963                         self.current_ref = self.getCurrentSelection()
964                         self.enterPath(self.current_ref)
965                 self.mutableList = self.getMutableList()
966                 # add all services from the current list to internal marked set in listboxservicecontent
967                 self.clearMarks() # this clears the internal marked set in the listboxservicecontent
968                 self.saved_title = self.getTitle()
969                 pos = self.saved_title.find(')')
970                 new_title = self.saved_title[:pos+1]
971                 if type == EDIT_ALTERNATIVES:
972                         self.bouquet_mark_edit = EDIT_ALTERNATIVES
973                         new_title += ' ' + _("[alternative edit]")
974                 else:
975                         self.bouquet_mark_edit = EDIT_BOUQUET
976                         if config.usage.multibouquet.value:
977                                 new_title += ' ' + _("[bouquet edit]")
978                         else:
979                                 new_title += ' ' + _("[favourite edit]")
980                 self.setTitle(new_title)
981                 self.__marked = self.servicelist.getRootServices()
982                 for x in self.__marked:
983                         self.servicelist.addMarked(eServiceReference(x))
984                 self["Service"].editmode = True
985
986         def endMarkedEdit(self, abort):
987                 if not abort and self.mutableList is not None:
988                         new_marked = set(self.servicelist.getMarked())
989                         old_marked = set(self.__marked)
990                         removed = old_marked - new_marked
991                         added = new_marked - old_marked
992                         changed = False
993                         for x in removed:
994                                 changed = True
995                                 self.mutableList.removeService(eServiceReference(x))
996                         for x in added:
997                                 changed = True
998                                 self.mutableList.addService(eServiceReference(x))
999                         if changed:
1000                                 if self.bouquet_mark_edit == EDIT_ALTERNATIVES and not new_marked and self.__marked:
1001                                         self.mutableList.addService(eServiceReference(self.__marked[0]))
1002                                 self.mutableList.flushChanges()
1003                 self.__marked = []
1004                 self.clearMarks()
1005                 self.bouquet_mark_edit = OFF
1006                 self.mutableList = None
1007                 self.setTitle(self.saved_title)
1008                 self.saved_title = None
1009                 # self.servicePath is just a reference to servicePathTv or Radio...
1010                 # so we never ever do use the asignment operator in self.servicePath
1011                 del self.servicePath[:] # remove all elements
1012                 self.servicePath += self.savedPath # add saved elements
1013                 del self.savedPath
1014                 self.setRoot(self.servicePath[-1])
1015                 if self.current_ref:
1016                         self.setCurrentSelection(self.current_ref)
1017                         self.current_ref = None
1018
1019         def clearMarks(self):
1020                 self.servicelist.clearMarks()
1021
1022         def doMark(self):
1023                 ref = self.servicelist.getCurrent()
1024                 if self.servicelist.isMarked(ref):
1025                         self.servicelist.removeMarked(ref)
1026                 else:
1027                         self.servicelist.addMarked(ref)
1028
1029         def removeCurrentEntry(self, bouquet=False):
1030                 if self.confirmRemove:
1031                         list = [(_("yes"), True), (_("no"), False), (_("yes") + " " + _("and never ask again this session again"), "never")]
1032                         self.session.openWithCallback(boundFunction(self.removeCurrentEntryCallback, bouquet), MessageBox, _("Are you sure to remove this entry?"), list=list)
1033                 else:
1034                         self.removeCurrentEntryCallback(bouquet, True)
1035
1036         def removeCurrentEntryCallback(self, bouquet, answer):
1037                 if answer:
1038                         if answer == "never":
1039                                 self.confirmRemove = False
1040                         if bouquet:
1041                                 self.removeBouquet()
1042                         else:
1043                                 self.removeCurrentService()
1044
1045         def removeCurrentService(self, bouquet=False):
1046                 self.editMode = True
1047                 ref = self.servicelist.getCurrent()
1048                 mutableList = self.getMutableList()
1049                 if ref.valid() and mutableList is not None:
1050                         if not mutableList.removeService(ref):
1051                                 mutableList.flushChanges() #FIXME dont flush on each single removed service
1052                                 self.servicelist.removeCurrent()
1053                                 self.servicelist.resetRoot()
1054                                 if not bouquet and ref == self.session.nav.getCurrentlyPlayingServiceOrGroup():
1055                                         self.channelSelected(doClose=False)
1056
1057         def addServiceToBouquet(self, dest, service=None):
1058                 mutableList = self.getMutableList(dest)
1059                 if not mutableList is None:
1060                         if service is None: #use current selected service
1061                                 service = self.servicelist.getCurrent()
1062                         if not mutableList.addService(service):
1063                                 mutableList.flushChanges()
1064                                 # do some voodoo to check if current_root is equal to dest
1065                                 cur_root = self.getRoot();
1066                                 str1 = cur_root and cur_root.toString() or -1
1067                                 str2 = dest.toString()
1068                                 pos1 = str1.find("FROM BOUQUET")
1069                                 pos2 = str2.find("FROM BOUQUET")
1070                                 if pos1 != -1 and pos2 != -1 and str1[pos1:] == str2[pos2:]:
1071                                         self.servicelist.addService(service)
1072                                 self.servicelist.resetRoot()
1073
1074         def toggleMoveMode(self, select=False):
1075                 self.editMode = True
1076                 if self.movemode:
1077                         if self.entry_marked:
1078                                 self.toggleMoveMarked() # unmark current entry
1079                         self.movemode = False
1080                         self.mutableList.flushChanges() # FIXME add check if changes was made
1081                         self.mutableList = None
1082                         self.setTitle(self.saved_title)
1083                         self.saved_title = None
1084                         self.servicelist.resetRoot()
1085                         self.servicelist.l.setHideNumberMarker(config.usage.hide_number_markers.value)
1086                         self.servicelist.setCurrent(self.servicelist.getCurrent())
1087                 else:
1088                         self.mutableList = self.getMutableList()
1089                         self.movemode = True
1090                         select and self.toggleMoveMarked()
1091                         self.saved_title = self.getTitle()
1092                         pos = self.saved_title.find(')')
1093                         self.setTitle(self.saved_title[:pos+1] + ' ' + _("[move mode]") + self.saved_title[pos+1:]);
1094                         self.servicelist.l.setHideNumberMarker(False)
1095                         self.servicelist.setCurrent(self.servicelist.getCurrent())
1096                 self["Service"].editmode = True
1097
1098         def handleEditCancel(self):
1099                 if self.movemode: #movemode active?
1100                         self.toggleMoveMode() # disable move mode
1101                 elif self.bouquet_mark_edit != OFF:
1102                         self.endMarkedEdit(True) # abort edit mode
1103
1104         def toggleMoveMarked(self):
1105                 if self.entry_marked:
1106                         self.servicelist.setCurrentMarked(False)
1107                         self.entry_marked = False
1108                         self.pathChangeDisabled = False # re-enable path change
1109                 else:
1110                         self.servicelist.setCurrentMarked(True)
1111                         self.entry_marked = True
1112                         self.pathChangeDisabled = True # no path change allowed in movemod
1113
1114         def doContext(self):
1115                 self.session.openWithCallback(self.exitContext, ChannelContextMenu, self)
1116
1117         def exitContext(self, close=False):
1118                 if close:
1119                         self.cancel()
1120
1121 MODE_TV = 0
1122 MODE_RADIO = 1
1123
1124 # type 1 = digital television service
1125 # type 4 = nvod reference service (NYI)
1126 # type 17 = MPEG-2 HD digital television service
1127 # type 22 = advanced codec SD digital television
1128 # type 24 = advanced codec SD NVOD reference service (NYI)
1129 # type 25 = advanced codec HD digital television
1130 # type 27 = advanced codec HD NVOD reference service (NYI)
1131 # type 2 = digital radio sound service
1132 # type 10 = advanced codec digital radio sound service
1133
1134 service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 22) || (type == 25) || (type == 134) || (type == 195)'
1135 service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2) || (type == 10)'
1136
1137 class ChannelSelectionBase(Screen):
1138         def __init__(self, session):
1139                 Screen.__init__(self, session)
1140
1141                 self["key_red"] = Button(_("All"))
1142                 self["key_green"] = Button(_("Satellites"))
1143                 self["key_yellow"] = Button(_("Provider"))
1144                 self["key_blue"] = Button(_("Favourites"))
1145
1146                 self["list"] = ServiceList(self)
1147                 self.servicelist = self["list"]
1148
1149                 self.numericalTextInput = NumericalTextInput(handleTimeout=False)
1150                 self.numericalTextInput.setUseableChars(u'1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ')
1151
1152                 self.servicePathTV = [ ]
1153                 self.servicePathRadio = [ ]
1154                 self.servicePath = [ ]
1155                 self.history = [ ]
1156                 self.rootChanged = False
1157                 self.startRoot = None
1158                 self.selectionNumber = ""
1159                 self.clearNumberSelectionNumberTimer = eTimer()
1160                 self.clearNumberSelectionNumberTimer.callback.append(self.clearNumberSelectionNumber)
1161
1162                 self.mode = MODE_TV
1163                 self.dopipzap = False
1164                 self.pathChangeDisabled = False
1165                 self.movemode = False
1166                 self.showSatDetails = False
1167
1168                 self["ChannelSelectBaseActions"] = NumberActionMap(["ChannelSelectBaseActions", "NumberActions", "InputAsciiActions"],
1169                         {
1170                                 "showFavourites": self.showFavourites,
1171                                 "showAllServices": self.showAllServices,
1172                                 "showProviders": self.showProviders,
1173                                 "showSatellites": boundFunction(self.showSatellites, changeMode=True),
1174                                 "nextBouquet": self.nextBouquet,
1175                                 "prevBouquet": self.prevBouquet,
1176                                 "nextMarker": self.nextMarker,
1177                                 "prevMarker": self.prevMarker,
1178                                 "gotAsciiCode": self.keyAsciiCode,
1179                                 "keyLeft": self.keyLeft,
1180                                 "keyRight": self.keyRight,
1181                                 "keyRecord": self.keyRecord,
1182                                 "1": self.keyNumberGlobal,
1183                                 "2": self.keyNumberGlobal,
1184                                 "3": self.keyNumberGlobal,
1185                                 "4": self.keyNumberGlobal,
1186                                 "5": self.keyNumberGlobal,
1187                                 "6": self.keyNumberGlobal,
1188                                 "7": self.keyNumberGlobal,
1189                                 "8": self.keyNumberGlobal,
1190                                 "9": self.keyNumberGlobal,
1191                                 "0": self.keyNumber0
1192                         }, -2)
1193                 self.maintitle = _("Channel selection")
1194                 self.recallBouquetMode()
1195
1196         def getBouquetNumOffset(self, bouquet):
1197                 if not config.usage.multibouquet.value:
1198                         return 0
1199                 str = bouquet.toString()
1200                 offset = 0
1201                 if 'userbouquet.' in bouquet.toCompareString():
1202                         serviceHandler = eServiceCenter.getInstance()
1203                         servicelist = serviceHandler.list(bouquet)
1204                         if not servicelist is None:
1205                                 while True:
1206                                         serviceIterator = servicelist.getNext()
1207                                         if not serviceIterator.valid(): #check if end of list
1208                                                 break
1209                                         number = serviceIterator.getChannelNum()
1210                                         if number > 0:
1211                                                 offset = number - 1
1212                                                 break
1213                 return offset
1214
1215         def recallBouquetMode(self):
1216                 if self.mode == MODE_TV:
1217                         self.service_types = service_types_tv
1218                         if config.usage.multibouquet.value:
1219                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.tv" ORDER BY bouquet'
1220                         else:
1221                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)
1222                 else:
1223                         self.service_types = service_types_radio
1224                         if config.usage.multibouquet.value:
1225                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.radio" ORDER BY bouquet'
1226                         else:
1227                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(self.service_types)
1228                 self.bouquet_root = eServiceReference(self.bouquet_rootstr)
1229
1230         def setTvMode(self):
1231                 self.mode = MODE_TV
1232                 self.servicePath = self.servicePathTV
1233                 self.recallBouquetMode()
1234                 title = self.maintitle
1235                 pos = title.find(" (")
1236                 if pos != -1:
1237                         title = title[:pos]
1238                 title += _(" (TV)")
1239                 self.setTitle(title)
1240
1241         def setRadioMode(self):
1242                 self.mode = MODE_RADIO
1243                 self.servicePath = self.servicePathRadio
1244                 self.recallBouquetMode()
1245                 title = self.maintitle
1246                 pos = title.find(" (")
1247                 if pos != -1:
1248                         title = title[:pos]
1249                 title += _(" (Radio)")
1250                 self.setTitle(title)
1251
1252         def setRoot(self, root, justSet=False):
1253                 if self.startRoot is None:
1254                         self.startRoot = self.getRoot()
1255                 path = root.getPath()
1256                 isBouquet = 'FROM BOUQUET' in path and (root.flags & eServiceReference.isDirectory)
1257                 inBouquetRootList = 'FROM BOUQUET "bouquets.' in path #FIXME HACK
1258                 if not inBouquetRootList and isBouquet:
1259                         self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
1260                 else:
1261                         self.servicelist.setMode(ServiceList.MODE_NORMAL)
1262                 self.servicelist.setRoot(root, justSet)
1263                 self.rootChanged = True
1264                 self.buildTitleString()
1265
1266         def removeModeStr(self, str):
1267                 if self.mode == MODE_TV:
1268                         pos = str.find(_(" (TV)"))
1269                 else:
1270                         pos = str.find(_(" (Radio)"))
1271                 if pos != -1:
1272                         return str[:pos]
1273                 return str
1274
1275         def getServiceName(self, ref):
1276                 str = self.removeModeStr(ServiceReference(ref).getServiceName())
1277                 if 'User - bouquets' in str:
1278                         return _("User - bouquets")
1279                 if not str:
1280                         pathstr = ref.getPath()
1281                         if 'FROM PROVIDERS' in pathstr:
1282                                 return _("Provider")
1283                         if 'FROM SATELLITES' in pathstr:
1284                                 return _("Satellites")
1285                         if ') ORDER BY name' in pathstr:
1286                                 return _("All")
1287                 return str
1288
1289         def buildTitleString(self):
1290                 titleStr = self.getTitle()
1291                 pos = titleStr.find(']')
1292                 if pos == -1:
1293                         pos = titleStr.find(')')
1294                 if pos != -1:
1295                         titleStr = titleStr[:pos+1]
1296                         Len = len(self.servicePath)
1297                         if Len > 0:
1298                                 base_ref = self.servicePath[0]
1299                                 if Len > 1:
1300                                         end_ref = self.servicePath[Len-1]
1301                                 else:
1302                                         end_ref = None
1303                                 nameStr = self.getServiceName(base_ref)
1304                                 titleStr += ' - ' + nameStr
1305                                 if end_ref is not None:
1306                                         if Len > 2:
1307                                                 titleStr += '/../'
1308                                         else:
1309                                                 titleStr += '/'
1310                                         nameStr = self.getServiceName(end_ref)
1311                                         titleStr += nameStr
1312                                 self.setTitle(titleStr)
1313
1314         def moveUp(self):
1315                 self.servicelist.moveUp()
1316
1317         def moveDown(self):
1318                 self.servicelist.moveDown()
1319
1320         def clearPath(self):
1321                 del self.servicePath[:]
1322
1323         def enterPath(self, ref, justSet=False):
1324                 self.servicePath.append(ref)
1325                 self.setRoot(ref, justSet)
1326
1327         def enterUserbouquet(self, root, save_root=True):
1328                 self.clearPath()
1329                 self.recallBouquetMode()
1330                 if self.bouquet_root:
1331                         self.enterPath(self.bouquet_root)
1332                 self.enterPath(root)
1333                 self.startRoot = None
1334                 if save_root:
1335                         self.saveRoot()
1336
1337         def pathUp(self, justSet=False):
1338                 prev = self.servicePath.pop()
1339                 if self.servicePath:
1340                         current = self.servicePath[-1]
1341                         self.setRoot(current, justSet)
1342                         if not justSet:
1343                                 self.setCurrentSelection(prev)
1344                 return prev
1345
1346         def isBasePathEqual(self, ref):
1347                 if len(self.servicePath) > 1 and self.servicePath[0] == ref:
1348                         return True
1349                 return False
1350
1351         def isPrevPathEqual(self, ref):
1352                 length = len(self.servicePath)
1353                 if length > 1 and self.servicePath[length-2] == ref:
1354                         return True
1355                 return False
1356
1357         def preEnterPath(self, refstr):
1358                 return False
1359
1360         def showAllServices(self):
1361                 if not self.pathChangeDisabled:
1362                         refstr = '%s ORDER BY name'%(self.service_types)
1363                         if not self.preEnterPath(refstr):
1364                                 ref = eServiceReference(refstr)
1365                                 currentRoot = self.getRoot()
1366                                 if currentRoot is None or currentRoot != ref:
1367                                         self.clearPath()
1368                                         self.enterPath(ref)
1369                                         self.setCurrentSelectionAlternative(self.session.nav.getCurrentlyPlayingServiceOrGroup())
1370
1371         def showSatellites(self, changeMode=False):
1372                 if not self.pathChangeDisabled:
1373                         refstr = '%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)
1374                         if not self.preEnterPath(refstr):
1375                                 ref = eServiceReference(refstr)
1376                                 justSet=False
1377                                 prev = None
1378
1379                                 if self.isBasePathEqual(ref):
1380                                         if self.isPrevPathEqual(ref):
1381                                                 justSet=True
1382                                         prev = self.pathUp(justSet)
1383                                 else:
1384                                         currentRoot = self.getRoot()
1385                                         if currentRoot is None or currentRoot != ref:
1386                                                 justSet=True
1387                                                 self.clearPath()
1388                                                 self.enterPath(ref, True)
1389                                         if changeMode and currentRoot and currentRoot == ref:
1390                                                 self.showSatDetails = not self.showSatDetails
1391                                                 justSet = True
1392                                                 self.clearPath()
1393                                                 self.enterPath(ref, True)
1394                                 if justSet:
1395                                         addCableAndTerrestrialLater = []
1396                                         serviceHandler = eServiceCenter.getInstance()
1397                                         servicelist = serviceHandler.list(ref)
1398                                         if not servicelist is None:
1399                                                 while True:
1400                                                         service = servicelist.getNext()
1401                                                         if not service.valid(): #check if end of list
1402                                                                 break
1403                                                         unsigned_orbpos = service.getUnsignedData(4) >> 16
1404                                                         orbpos = service.getData(4) >> 16
1405                                                         if orbpos < 0:
1406                                                                 orbpos += 3600
1407                                                         if "FROM PROVIDER" in service.getPath():
1408                                                                 service_type = self.showSatDetails and _("Providers")
1409                                                         elif ("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) in service.getPath():
1410                                                                 service_type = self.showSatDetails and _("New")
1411                                                         else:
1412                                                                 service_type = _("Services")
1413                                                         if service_type:
1414                                                                 if unsigned_orbpos == 0xFFFF: #Cable
1415                                                                         service_name = _("Cable")
1416                                                                         addCableAndTerrestrialLater.append(("%s - %s" % (service_name, service_type), service.toString()))                      
1417                                                                 elif unsigned_orbpos == 0xEEEE: #Terrestrial
1418                                                                         service_name = _("Terrestrial")
1419                                                                         addCableAndTerrestrialLater.append(("%s - %s" % (service_name, service_type), service.toString()))                      
1420                                                                 else:
1421                                                                         try:
1422                                                                                 service_name = str(nimmanager.getSatDescription(orbpos))
1423                                                                         except:
1424                                                                                 if orbpos > 1800: # west
1425                                                                                         orbpos = 3600 - orbpos
1426                                                                                         h = _("W")
1427                                                                                 else:
1428                                                                                         h = _("E")
1429                                                                                 service_name = ("%d.%d" + h) % (orbpos / 10, orbpos % 10)
1430                                                                         service.setName("%s - %s" % (service_name, service_type))
1431                                                                         self.servicelist.addService(service)
1432                                                 cur_ref = self.session.nav.getCurrentlyPlayingServiceReference()
1433                                                 self.servicelist.l.sort()
1434                                                 if cur_ref:
1435                                                         pos = self.service_types.rfind(':')
1436                                                         refstr = '%s (channelID == %08x%04x%04x) && %s ORDER BY name' %(self.service_types[:pos+1],
1437                                                                 cur_ref.getUnsignedData(4), # NAMESPACE
1438                                                                 cur_ref.getUnsignedData(2), # TSID
1439                                                                 cur_ref.getUnsignedData(3), # ONID
1440                                                                 self.service_types[pos+1:])
1441                                                         ref = eServiceReference(refstr)
1442                                                         ref.setName(_("Current transponder"))
1443                                                         self.servicelist.addService(ref, beforeCurrent=True)
1444                                                 for (service_name, service_ref) in addCableAndTerrestrialLater:
1445                                                         ref = eServiceReference(service_ref)
1446                                                         ref.setName(service_name)
1447                                                         self.servicelist.addService(ref, beforeCurrent=True)
1448                                                 self.servicelist.l.FillFinished()
1449                                                 if prev is not None:
1450                                                         self.setCurrentSelection(prev)
1451                                                 elif cur_ref:
1452                                                         refstr = cur_ref.toString()
1453                                                         op = "".join(refstr.split(':', 10)[6:7])
1454                                                         if len(op) >= 4:
1455                                                                 hop = int(op[:-4],16)
1456                                                                 if len(op) >= 7 and not op.endswith('0000'):
1457                                                                         op = op[:-4] + '0000'
1458                                                                 refstr = '1:7:0:0:0:0:%s:0:0:0:(satellitePosition == %s) && %s ORDER BY name' % (op, hop, self.service_types[self.service_types.rfind(':')+1:])
1459                                                                 self.setCurrentSelectionAlternative(eServiceReference(refstr))
1460
1461         def showProviders(self):
1462                 if not self.pathChangeDisabled:
1463                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
1464                         if not self.preEnterPath(refstr):
1465                                 ref = eServiceReference(refstr)
1466                                 if self.isBasePathEqual(ref):
1467                                         self.pathUp()
1468                                 else:
1469                                         currentRoot = self.getRoot()
1470                                         if currentRoot is None or currentRoot != ref:
1471                                                 self.clearPath()
1472                                                 self.enterPath(ref)
1473                                                 service = self.session.nav.getCurrentService()
1474                                                 if service:
1475                                                         info = service.info()
1476                                                         if info:
1477                                                                 provider = info.getInfoString(iServiceInformation.sProvider)
1478                                                                 refstr = '1:7:0:0:0:0:0:0:0:0:(provider == \"%s\") && %s ORDER BY name:%s' % (provider, self.service_types[self.service_types.rfind(':')+1:],provider)
1479                                                                 self.setCurrentSelectionAlternative(eServiceReference(refstr))
1480
1481         def changeBouquet(self, direction):
1482                 if not self.pathChangeDisabled:
1483                         if len(self.servicePath) > 1:
1484                                 #when enter satellite root list we must do some magic stuff..
1485                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
1486                                 if self.isBasePathEqual(ref):
1487                                         self.showSatellites()
1488                                 else:
1489                                         self.pathUp()
1490                                 if direction < 0:
1491                                         self.moveUp()
1492                                 else:
1493                                         self.moveDown()
1494                                 ref = self.getCurrentSelection()
1495                                 self.enterPath(ref)
1496
1497         def inBouquet(self):
1498                 if self.servicePath and self.servicePath[0] == self.bouquet_root:
1499                         return True
1500                 return False
1501
1502         def atBegin(self):
1503                 return self.servicelist.atBegin()
1504
1505         def atEnd(self):
1506                 return self.servicelist.atEnd()
1507
1508         def nextBouquet(self):
1509                 if self.shown and config.usage.oldstyle_channel_select_controls.value:
1510                         self.servicelist.instance.moveSelection(self.servicelist.instance.pageUp)
1511                 elif "reverseB" in config.usage.servicelist_cursor_behavior.value:
1512                         self.changeBouquet(-1)
1513                 else:
1514                         self.changeBouquet(+1)
1515
1516         def prevBouquet(self):
1517                 if self.shown and config.usage.oldstyle_channel_select_controls.value:
1518                         self.servicelist.instance.moveSelection(self.servicelist.instance.pageDown)
1519                 elif "reverseB" in config.usage.servicelist_cursor_behavior.value:
1520                         self.changeBouquet(+1)
1521                 else:
1522                         self.changeBouquet(-1)
1523
1524         def keyLeft(self):
1525                 if config.usage.oldstyle_channel_select_controls.value:
1526                         self.changeBouquet(-1)
1527                 else:
1528                         self.servicelist.instance.moveSelection(self.servicelist.instance.pageUp)
1529
1530         def keyRight(self):
1531                 if config.usage.oldstyle_channel_select_controls.value:
1532                         self.changeBouquet(+1)
1533                 else:
1534                         self.servicelist.instance.moveSelection(self.servicelist.instance.pageDown)
1535
1536         def keyRecord(self):
1537                 ref = self.getCurrentSelection()
1538                 if ref and not(ref.flags & (eServiceReference.isMarker|eServiceReference.isDirectory)):
1539                         Screens.InfoBar.InfoBar.instance.instantRecord(serviceRef=ref)
1540
1541         def showFavourites(self):
1542                 if not self.pathChangeDisabled:
1543                         if not self.preEnterPath(self.bouquet_rootstr):
1544                                 if self.isBasePathEqual(self.bouquet_root):
1545                                         self.pathUp()
1546                                 else:
1547                                         currentRoot = self.getRoot()
1548                                         if currentRoot is None or currentRoot != self.bouquet_root:
1549                                                 self.clearPath()
1550                                                 self.enterPath(self.bouquet_root)
1551
1552         def keyNumber0(self, number):
1553                 if len(self.servicePath) > 1 and not self.selectionNumber:
1554                         self.keyGoUp()
1555                 else:
1556                         self.keyNumberGlobal(number)
1557
1558         def keyNumberGlobal(self, number):
1559                 if self.isBasePathEqual(self.bouquet_root):
1560                         if hasattr(self, "editMode") and self.editMode:
1561                                 if number == 2:
1562                                         self.renameEntry()
1563                                 if number == 6:
1564                                         self.toggleMoveMode(select=True)
1565                                 if number == 8:
1566                                         self.removeCurrentEntry(bouquet=False)
1567                         else:
1568                                 self.numberSelectionActions(number)
1569                 else:
1570                         current_root = self.getRoot()
1571                         if  current_root and 'FROM BOUQUET "bouquets.' in current_root.getPath():
1572                                 if hasattr(self, "editMode") and self.editMode:
1573                                         if number == 2:
1574                                                 self.renameEntry()
1575                                         if number == 6:
1576                                                 self.toggleMoveMode(select=True)
1577                                         if number == 8:
1578                                                 self.removeCurrentEntry(bouquet=True)
1579                                 else:
1580                                         self.numberSelectionActions(number)
1581                         else:
1582                                 unichar = self.numericalTextInput.getKey(number)
1583                                 charstr = unichar.encode("utf-8")
1584                                 if len(charstr) == 1:
1585                                         self.servicelist.moveToChar(charstr[0])
1586
1587         def numberSelectionActions(self, number):
1588                 if not(hasattr(self, "movemode") and self.movemode):
1589                         if len(self.selectionNumber)>4:
1590                                 self.clearNumberSelectionNumber()
1591                         self.selectionNumber = self.selectionNumber + str(number)
1592                         ref, bouquet = Screens.InfoBar.InfoBar.instance.searchNumber(int(self.selectionNumber), bouquet=self.getRoot())
1593                         if ref:
1594                                 if not ref.flags & eServiceReference.isMarker:
1595                                         self.enterUserbouquet(bouquet, save_root=False)
1596                                         self.servicelist.setCurrent(ref)
1597                                 self.clearNumberSelectionNumberTimer.start(1000, True)
1598                         else:
1599                                 self.clearNumberSelectionNumber()
1600
1601         def clearNumberSelectionNumber(self):
1602                 self.clearNumberSelectionNumberTimer.stop()
1603                 self.selectionNumber = ""
1604
1605         def keyAsciiCode(self):
1606                 unichar = unichr(getPrevAsciiCode())
1607                 charstr = unichar.encode("utf-8")
1608                 if len(charstr) == 1:
1609                         self.servicelist.moveToChar(charstr[0])
1610
1611         def getRoot(self):
1612                 return self.servicelist.getRoot()
1613
1614         def getCurrentSelection(self):
1615                 return self.servicelist.getCurrent()
1616
1617         def setCurrentSelection(self, service):
1618                 if service:
1619                         self.servicelist.setCurrent(service, adjust=False)
1620
1621         def setCurrentSelectionAlternative(self, ref):
1622                 if self.bouquet_mark_edit == EDIT_ALTERNATIVES and not (ref.flags & eServiceReference.isDirectory):
1623                         for markedService in self.servicelist.getMarked():
1624                                 markedService = eServiceReference(markedService)
1625                                 self.setCurrentSelection(markedService)
1626                                 if markedService == self.getCurrentSelection():
1627                                         return
1628                 self.setCurrentSelection(ref)
1629
1630         def getBouquetList(self):
1631                 bouquets = [ ]
1632                 serviceHandler = eServiceCenter.getInstance()
1633                 if config.usage.multibouquet.value:
1634                         list = serviceHandler.list(self.bouquet_root)
1635                         if list:
1636                                 while True:
1637                                         s = list.getNext()
1638                                         if not s.valid():
1639                                                 break
1640                                         if s.flags & eServiceReference.isDirectory:
1641                                                 info = serviceHandler.info(s)
1642                                                 if info:
1643                                                         bouquets.append((info.getName(s), s))
1644                                 return bouquets
1645                 else:
1646                         info = serviceHandler.info(self.bouquet_root)
1647                         if info:
1648                                 bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
1649                         return bouquets
1650                 return None
1651
1652         def keyGoUp(self):
1653                 if len(self.servicePath) > 1:
1654                         if self.isBasePathEqual(self.bouquet_root):
1655                                 self.showFavourites()
1656                         else:
1657                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
1658                                 if self.isBasePathEqual(ref):
1659                                         self.showSatellites()
1660                                 else:
1661                                         ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
1662                                         if self.isBasePathEqual(ref):
1663                                                 self.showProviders()
1664                                         else:
1665                                                 self.showAllServices()
1666
1667         def nextMarker(self):
1668                 self.servicelist.moveToNextMarker()
1669
1670         def prevMarker(self):
1671                 self.servicelist.moveToPrevMarker()
1672
1673         def gotoCurrentServiceOrProvider(self, ref):
1674                 str = ref.toString()
1675                 if _("Providers") in str:
1676                         service = self.session.nav.getCurrentService()
1677                         if service:
1678                                 info = service.info()
1679                                 if info:
1680                                         provider = info.getInfoString(iServiceInformation.sProvider)
1681                                         op = int(self.session.nav.getCurrentlyPlayingServiceOrGroup().toString().split(':')[6][:-4] or "0",16)
1682                                         refstr = '1:7:0:0:0:0:0:0:0:0:(provider == \"%s\") && (satellitePosition == %s) && %s ORDER BY name:%s' % (provider, op, self.service_types[self.service_types.rfind(':')+1:],provider)
1683                                         self.servicelist.setCurrent(eServiceReference(refstr))
1684                 elif not self.isBasePathEqual(self.bouquet_root) or self.bouquet_mark_edit == EDIT_ALTERNATIVES:
1685                         self.setCurrentSelectionAlternative(self.session.nav.getCurrentlyPlayingServiceOrGroup())
1686
1687 HISTORYSIZE = 20
1688
1689 #config for lastservice
1690 config.tv = ConfigSubsection()
1691 config.tv.lastservice = ConfigText()
1692 config.tv.lastroot = ConfigText()
1693 config.radio = ConfigSubsection()
1694 config.radio.lastservice = ConfigText()
1695 config.radio.lastroot = ConfigText()
1696 config.servicelist = ConfigSubsection()
1697 config.servicelist.lastmode = ConfigText(default = "tv")
1698 config.servicelist.startupservice = ConfigText()
1699 config.servicelist.startuproot = ConfigText()
1700 config.servicelist.startupmode = ConfigText(default = "tv")
1701
1702 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, SelectionEventInfo):
1703         def __init__(self, session):
1704                 ChannelSelectionBase.__init__(self,session)
1705                 ChannelSelectionEdit.__init__(self)
1706                 ChannelSelectionEPG.__init__(self)
1707                 SelectionEventInfo.__init__(self)
1708
1709                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1710                         {
1711                                 "cancel": self.cancel,
1712                                 "ok": self.channelSelected,
1713                                 "keyRadio": self.doRadioButton,
1714                                 "keyTV": self.doTVButton,
1715                         })
1716
1717                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1718                         {
1719                                 iPlayableService.evStart: self.__evServiceStart,
1720                                 iPlayableService.evEnd: self.__evServiceEnd
1721                         })
1722
1723                 self.startServiceRef = None
1724
1725                 self.history = [ ]
1726                 self.history_pos = 0
1727
1728                 if config.servicelist.startupservice.value and config.servicelist.startuproot.value:
1729                         config.servicelist.lastmode.value = config.servicelist.startupmode.value
1730                         if config.servicelist.lastmode.value == "tv":
1731                                 config.tv.lastservice.value = config.servicelist.startupservice.value
1732                                 config.tv.lastroot.value = config.servicelist.startuproot.value
1733                         elif config.servicelist.lastmode.value == "radio":
1734                                 config.radio.lastservice.value = config.servicelist.startupservice.value
1735                                 config.radio.lastroot.value = config.servicelist.startuproot.value
1736
1737                 self.lastservice = config.tv.lastservice
1738                 self.lastroot = config.tv.lastroot
1739                 self.revertMode = None
1740                 config.usage.multibouquet.addNotifier(self.multibouquet_config_changed)
1741                 self.new_service_played = False
1742                 self.dopipzap = False
1743                 self.onExecBegin.append(self.asciiOn)
1744                 self.mainScreenMode = None
1745                 self.mainScreenRoot = None
1746
1747                 self.lastChannelRootTimer = eTimer()
1748                 self.lastChannelRootTimer.callback.append(self.__onCreate)
1749                 self.lastChannelRootTimer.start(100,True)
1750                 self.pipzaptimer = eTimer()
1751
1752         def asciiOn(self):
1753                 rcinput = eRCInput.getInstance()
1754                 rcinput.setKeyboardMode(rcinput.kmAscii)
1755
1756         def asciiOff(self):
1757                 rcinput = eRCInput.getInstance()
1758                 rcinput.setKeyboardMode(rcinput.kmNone)
1759
1760         def multibouquet_config_changed(self, val):
1761                 self.recallBouquetMode()
1762
1763         def __evServiceStart(self):
1764                 if self.dopipzap and hasattr(self.session, 'pip'):
1765                         self.servicelist.setPlayableIgnoreService(self.session.pip.getCurrentServiceReference() or eServiceReference())
1766                 else:
1767                         service = self.session.nav.getCurrentService()
1768                         if service:
1769                                 info = service.info()
1770                                 if info:
1771                                         refstr = info.getInfoString(iServiceInformation.sServiceref)
1772                                         self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1773
1774         def __evServiceEnd(self):
1775                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1776
1777         def setMode(self):
1778                 self.rootChanged = True
1779                 self.restoreRoot()
1780                 lastservice = eServiceReference(self.lastservice.value)
1781                 if lastservice.valid():
1782                         self.setCurrentSelection(lastservice)
1783
1784         def doTVButton(self):
1785                 if self.mode == MODE_TV:
1786                         self.channelSelected(doClose = False)
1787                 else:
1788                         self.setModeTv()
1789
1790         def setModeTv(self):
1791                 if self.revertMode is None:
1792                         self.revertMode = self.mode
1793                 self.lastservice = config.tv.lastservice
1794                 self.lastroot = config.tv.lastroot
1795                 config.servicelist.lastmode.value = "tv"
1796                 self.setTvMode()
1797                 self.setMode()
1798
1799         def doRadioButton(self):
1800                 if self.mode == MODE_RADIO:
1801                         self.channelSelected(doClose=False)
1802                 else:
1803                         self.setModeRadio()
1804
1805         def setModeRadio(self):
1806                 if self.revertMode is None:
1807                         self.revertMode = self.mode
1808                 if config.usage.e1like_radio_mode.value:
1809                         self.lastservice = config.radio.lastservice
1810                         self.lastroot = config.radio.lastroot
1811                         config.servicelist.lastmode.value = "radio"
1812                         self.setRadioMode()
1813                         self.setMode()
1814
1815         def __onCreate(self):
1816                 if config.usage.e1like_radio_mode.value:
1817                         if config.servicelist.lastmode.value == "tv":
1818                                 self.setModeTv()
1819                         else:
1820                                 self.setModeRadio()
1821                 else:
1822                         self.setModeTv()
1823                 lastservice = eServiceReference(self.lastservice.value)
1824                 if lastservice.valid():
1825                         self.zap()
1826
1827         def channelSelected(self, doClose = True):
1828                 if config.usage.channelselection_preview.value and self.getCurrentSelection() != self.session.nav.getCurrentlyPlayingServiceOrGroup():
1829                         doClose = False
1830                 if not self.startServiceRef and not doClose:
1831                         self.startServiceRef = self.session.nav.getCurrentlyPlayingServiceOrGroup()
1832                 ref = self.getCurrentSelection()
1833                 if self.movemode and (self.isBasePathEqual(self.bouquet_root) or "userbouquet." in ref.toString()):
1834                         self.toggleMoveMarked()
1835                 elif (ref.flags & eServiceReference.flagDirectory) == eServiceReference.flagDirectory:
1836                         if Components.ParentalControl.parentalControl.isServicePlayable(ref, self.bouquetParentalControlCallback, self.session):
1837                                 self.enterPath(ref)
1838                                 self.gotoCurrentServiceOrProvider(ref)
1839                 elif self.bouquet_mark_edit != OFF:
1840                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1841                                 self.doMark()
1842                 elif not (ref.flags & eServiceReference.isMarker or ref.type == -1):
1843                         root = self.getRoot()
1844                         if not root or not (root.flags & eServiceReference.isGroup):
1845                                 self.zap(enable_pipzap=doClose, preview_zap=not doClose)
1846                                 self.asciiOff()
1847                                 if doClose:
1848                                         if self.dopipzap:
1849                                                 self.zapBack()
1850                                         self.startServiceRef = None
1851                                         self.startRoot = None
1852                                         self.correctChannelNumber()
1853                                         self.movemode and self.toggleMoveMode()
1854                                         self.editMode = False
1855                                         self.close(ref)
1856
1857         def bouquetParentalControlCallback(self, ref):
1858                 self.enterPath(ref)
1859                 self.gotoCurrentServiceOrProvider(ref)
1860
1861         def togglePipzap(self):
1862                 assert(self.session.pip)
1863                 title = self.instance.getTitle()
1864                 pos = title.find(" (")
1865                 if pos != -1:
1866                         title = title[:pos]
1867                 if self.dopipzap:
1868                         # Mark PiP as inactive and effectively deactivate pipzap
1869                         self.hidePipzapMessage()
1870                         self.dopipzap = False
1871
1872                         # Disable PiP if not playing a service
1873                         if self.session.pip.pipservice is None:
1874                                 self.session.pipshown = False
1875                                 del self.session.pip
1876                         self.__evServiceStart()
1877                         # Move to playing service
1878                         lastservice = eServiceReference(self.lastservice.value)
1879                         if lastservice.valid() and self.getCurrentSelection() != lastservice:
1880                                 self.setCurrentSelection(lastservice)
1881
1882                         title += _(" (TV)")
1883                 else:
1884                         # Mark PiP as active and effectively active pipzap
1885                         self.showPipzapMessage()
1886                         self.dopipzap = True
1887                         self.__evServiceStart()
1888                         # Move to service playing in pip (will not work with subservices)
1889                         self.setCurrentSelection(self.session.pip.getCurrentService())
1890
1891                         title += _(" (PiP)")
1892                 self.setTitle(title)
1893                 self.buildTitleString()
1894
1895         def showPipzapMessage(self):
1896                 time = config.usage.infobar_timeout.index
1897                 if time:
1898                         self.pipzaptimer.callback.append(self.hidePipzapMessage)
1899                         self.pipzaptimer.startLongTimer(time)
1900                 self.session.pip.active()
1901
1902         def hidePipzapMessage(self):
1903                 if self.pipzaptimer.isActive():
1904                         self.pipzaptimer.callback.remove(self.hidePipzapMessage)
1905                         self.pipzaptimer.stop()
1906                 self.session.pip.inactive()
1907
1908         #called from infoBar and channelSelected
1909         def zap(self, enable_pipzap=False, preview_zap=False, checkParentalControl=True, ref=None):
1910                 self.curRoot = self.startRoot
1911                 nref = ref or self.getCurrentSelection()
1912                 ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
1913                 if enable_pipzap and self.dopipzap:
1914                         ref = self.session.pip.getCurrentService()
1915                         if ref is None or ref != nref:
1916                                 nref = self.session.pip.resolveAlternatePipService(nref)
1917                                 if nref and (not checkParentalControl or Components.ParentalControl.parentalControl.isServicePlayable(nref, boundFunction(self.zap, enable_pipzap=True, checkParentalControl=False))):
1918                                         self.session.pip.playService(nref)
1919                                         self.__evServiceStart()
1920                                         self.showPipzapMessage()
1921                                 else:
1922                                         self.setStartRoot(self.curRoot)
1923                                         self.setCurrentSelection(ref)
1924                 elif ref is None or ref != nref:
1925                         Screens.InfoBar.InfoBar.instance.checkTimeshiftRunning(boundFunction(self.zapCheckTimeshiftCallback, enable_pipzap, preview_zap, nref))
1926                 elif not preview_zap:
1927                         self.saveRoot()
1928                         self.saveChannel(nref)
1929                         config.servicelist.lastmode.save()
1930                         self.setCurrentSelection(nref)
1931                         if self.startServiceRef is None or nref != self.startServiceRef:
1932                                 self.addToHistory(nref)
1933                         self.rootChanged = False
1934                         self.revertMode = None
1935
1936         def zapCheckTimeshiftCallback(self, enable_pipzap, preview_zap, nref, answer):
1937                 if answer:
1938                         self.new_service_played = True
1939                         self.session.nav.playService(nref)
1940                         if not preview_zap:
1941                                 self.saveRoot()
1942                                 self.saveChannel(nref)
1943                                 config.servicelist.lastmode.save()
1944                                 if self.startServiceRef is None or nref != self.startServiceRef:
1945                                         self.addToHistory(nref)
1946                                 if self.dopipzap:
1947                                         self.setCurrentSelection(self.session.pip.getCurrentService())
1948                                 else:
1949                                         self.mainScreenMode = config.servicelist.lastmode.value
1950                                         self.mainScreenRoot = self.getRoot()
1951                                 self.revertMode = None
1952                         else:
1953                                 Notifications.RemovePopup("Parental control")
1954                                 self.setCurrentSelection(nref)
1955                 else:
1956                         self.setStartRoot(self.curRoot)
1957                         self.setCurrentSelection(self.session.nav.getCurrentlyPlayingServiceOrGroup())
1958                 if not preview_zap:
1959                         self.hide()
1960
1961         def newServicePlayed(self):
1962                 ret = self.new_service_played
1963                 self.new_service_played = False
1964                 return ret
1965
1966         def addToHistory(self, ref):
1967                 if self.servicePath is not None:
1968                         tmp=self.servicePath[:]
1969                         tmp.append(ref)
1970                         try:
1971                                 del self.history[self.history_pos+1:]
1972                         except:
1973                                 pass
1974                         self.history.append(tmp)
1975                         hlen = len(self.history)
1976                         if hlen > HISTORYSIZE:
1977                                 del self.history[0]
1978                                 hlen -= 1
1979                         self.history_pos = hlen-1
1980
1981         def historyBack(self):
1982                 hlen = len(self.history)
1983                 currentPlayedRef = self.session.nav.getCurrentlyPlayingServiceOrGroup()
1984                 if hlen > 0 and currentPlayedRef and self.history[self.history_pos][-1] != currentPlayedRef:
1985                         self.addToHistory(currentPlayedRef)
1986                         hlen = len(self.history)
1987                 if hlen > 1 and self.history_pos > 0:
1988                         self.history_pos -= 1
1989                         self.setHistoryPath()
1990
1991         def historyNext(self):
1992                 hlen = len(self.history)
1993                 if hlen > 1 and self.history_pos < (hlen-1):
1994                         self.history_pos += 1
1995                         self.setHistoryPath()
1996
1997         def setHistoryPath(self, doZap=True):
1998                 path = self.history[self.history_pos][:]
1999                 ref = path.pop()
2000                 del self.servicePath[:]
2001                 self.servicePath += path
2002                 self.saveRoot()
2003                 root = path[-1]
2004                 cur_root = self.getRoot()
2005                 if cur_root and cur_root != root:
2006                         self.setRoot(root)
2007                 if doZap:
2008                         self.session.nav.playService(ref)
2009                 if self.dopipzap:
2010                         self.setCurrentSelection(self.session.pip.getCurrentService())
2011                 else:
2012                         self.setCurrentSelection(ref)
2013                 self.saveChannel(ref)
2014
2015         def saveRoot(self):
2016                 path = ''
2017                 for i in self.servicePath:
2018                         path += i.toString()
2019                         path += ';'
2020                 if path and path != self.lastroot.value:
2021                         if self.mode == MODE_RADIO and 'FROM BOUQUET "bouquets.tv"' in path:
2022                                 self.setModeTv()
2023                         elif self.mode == MODE_TV and 'FROM BOUQUET "bouquets.radio"' in path:
2024                                 self.setModeRadio()
2025                         self.lastroot.value = path
2026                         self.lastroot.save()
2027
2028         def restoreRoot(self):
2029                 tmp = [x for x in self.lastroot.value.split(';') if x != '']
2030                 current = [x.toString() for x in self.servicePath]
2031                 if tmp != current or self.rootChanged:
2032                         self.clearPath()
2033                         cnt = 0
2034                         for i in tmp:
2035                                 self.servicePath.append(eServiceReference(i))
2036                                 cnt += 1
2037                         if cnt:
2038                                 path = self.servicePath.pop()
2039                                 self.enterPath(path)
2040                         else:
2041                                 self.showFavourites()
2042                                 self.saveRoot()
2043                         self.rootChanged = False
2044
2045         def preEnterPath(self, refstr):
2046                 if self.servicePath and self.servicePath[0] != eServiceReference(refstr):
2047                         pathstr = self.lastroot.value
2048                         if pathstr is not None and refstr in pathstr:
2049                                 self.restoreRoot()
2050                                 lastservice = eServiceReference(self.lastservice.value)
2051                                 if lastservice.valid():
2052                                         self.setCurrentSelection(lastservice)
2053                                 return True
2054                 return False
2055
2056         def saveChannel(self, ref):
2057                 if ref is not None:
2058                         refstr = ref.toString()
2059                 else:
2060                         refstr = ""
2061                 if refstr != self.lastservice.value:
2062                         self.lastservice.value = refstr
2063                         self.lastservice.save()
2064
2065         def setCurrentServicePath(self, path, doZap=True):
2066                 if self.history:
2067                         self.history[self.history_pos] = path
2068                 else:
2069                         self.history.append(path)
2070                 self.setHistoryPath(doZap)
2071
2072         def getCurrentServicePath(self):
2073                 if self.history:
2074                         return self.history[self.history_pos]
2075                 return None
2076
2077         def recallPrevService(self):
2078                 hlen = len(self.history)
2079                 currentPlayedRef = self.session.nav.getCurrentlyPlayingServiceOrGroup()
2080                 if hlen > 0 and currentPlayedRef and self.history[self.history_pos][-1] != currentPlayedRef:
2081                         self.addToHistory(currentPlayedRef)
2082                         hlen = len(self.history)
2083                 if hlen > 1:
2084                         if self.history_pos == hlen-1:
2085                                 tmp = self.history[self.history_pos]
2086                                 self.history[self.history_pos] = self.history[self.history_pos-1]
2087                                 self.history[self.history_pos-1] = tmp
2088                         else:
2089                                 tmp = self.history[self.history_pos+1]
2090                                 self.history[self.history_pos+1] = self.history[self.history_pos]
2091                                 self.history[self.history_pos] = tmp
2092                         self.setHistoryPath()
2093
2094         def cancel(self):
2095                 if self.revertMode is None:
2096                         self.restoreRoot()
2097                         if self.dopipzap:
2098                                 # This unfortunately won't work with subservices
2099                                 self.setCurrentSelection(self.session.pip.getCurrentService())
2100                         else:
2101                                 lastservice = eServiceReference(self.lastservice.value)
2102                                 if lastservice.valid() and self.getCurrentSelection() != lastservice:
2103                                         self.setCurrentSelection(lastservice)
2104                 self.asciiOff()
2105                 self.zapBack()
2106                 self.correctChannelNumber()
2107                 self.editMode = False
2108                 self.close(None)
2109
2110         def zapBack(self):
2111                 if self.startServiceRef and self.session.nav.getCurrentlyPlayingServiceOrGroup() != self.startServiceRef:
2112                         self.setStartRoot(self.startRoot)
2113                         self.new_service_played = True
2114                         self.session.nav.playService(self.startServiceRef)
2115                         self.saveChannel(self.startServiceRef)
2116                 else:
2117                         self.restoreMode()
2118                 self.startServiceRef = None
2119                 self.startRoot = None
2120                 if self.dopipzap:
2121                         # This unfortunately won't work with subservices
2122                         self.setCurrentSelection(self.session.pip.getCurrentService())
2123                 else:
2124                         self.setCurrentSelection(self.session.nav.getCurrentlyPlayingServiceOrGroup())
2125
2126         def setStartRoot(self, root):
2127                 if root:
2128                         if self.revertMode == MODE_TV:
2129                                 self.setModeTv()
2130                         elif self.revertMode == MODE_RADIO:
2131                                 self.setModeRadio()
2132                         self.revertMode = None
2133                         self.enterUserbouquet(root)
2134
2135         def restoreMode(self):
2136                 if self.revertMode == MODE_TV:
2137                         self.setModeTv()
2138                 elif self.revertMode == MODE_RADIO:
2139                         self.setModeRadio()
2140                 self.revertMode = None
2141
2142         def correctChannelNumber(self):
2143                 current_ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
2144                 if self.dopipzap:
2145                         tmp_mode = config.servicelist.lastmode.value
2146                         tmp_root = self.getRoot()
2147                         tmp_ref = self.getCurrentSelection()
2148                         pip_ref = self.session.pip.getCurrentService()
2149                         if tmp_ref and pip_ref and tmp_ref != pip_ref:
2150                                 self.revertMode = None
2151                                 return
2152                         if self.mainScreenMode == "tv":
2153                                 self.setModeTv()
2154                         elif self.mainScreenMode == "radio":
2155                                 self.setModeRadio()
2156                         if self.mainScreenRoot:
2157                                 self.setRoot(self.mainScreenRoot)
2158                                 self.setCurrentSelection(current_ref)
2159                 selected_ref = self.getCurrentSelection()
2160                 if selected_ref and current_ref and selected_ref.getChannelNum() != current_ref.getChannelNum():
2161                         oldref = self.session.nav.currentlyPlayingServiceReference
2162                         if oldref and selected_ref == oldref or (oldref != current_ref and selected_ref == current_ref):
2163                                 self.session.nav.currentlyPlayingServiceOrGroup = selected_ref
2164                                 self.session.nav.pnav.navEvent(iPlayableService.evStart)
2165                 if self.dopipzap:
2166                         if tmp_mode == "tv":
2167                                 self.setModeTv()
2168                         elif tmp_mode == "radio":
2169                                 self.setModeRadio()
2170                         self.enterUserbouquet(tmp_root)
2171                         title = self.instance.getTitle()
2172                         pos = title.find(" (")
2173                         if pos != -1:
2174                                 title = title[:pos]
2175                                 title += _(" (PiP)")
2176                                 self.setTitle(title)
2177                                 self.buildTitleString()
2178                         if tmp_ref and pip_ref and tmp_ref.getChannelNum() != pip_ref.getChannelNum():
2179                                 self.session.pip.currentService = tmp_ref
2180                         self.setCurrentSelection(tmp_ref)
2181                 self.revertMode = None
2182
2183 class RadioInfoBar(Screen):
2184         def __init__(self, session):
2185                 Screen.__init__(self, session)
2186                 self["RdsDecoder"] = RdsDecoder(self.session.nav)
2187
2188 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, InfoBarBase, SelectionEventInfo):
2189         ALLOW_SUSPEND = True
2190
2191         def __init__(self, session, infobar):
2192                 ChannelSelectionBase.__init__(self, session)
2193                 ChannelSelectionEdit.__init__(self)
2194                 ChannelSelectionEPG.__init__(self)
2195                 InfoBarBase.__init__(self)
2196                 SelectionEventInfo.__init__(self)
2197                 self.infobar = infobar
2198                 self.startServiceRef = None
2199                 self.onLayoutFinish.append(self.onCreate)
2200
2201                 self.info = session.instantiateDialog(RadioInfoBar) # our simple infobar
2202
2203                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
2204                         {
2205                                 "keyTV": self.cancel,
2206                                 "keyRadio": self.cancel,
2207                                 "cancel": self.cancel,
2208                                 "ok": self.channelSelected,
2209                         })
2210
2211                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2212                         {
2213                                 iPlayableService.evStart: self.__evServiceStart,
2214                                 iPlayableService.evEnd: self.__evServiceEnd
2215                         })
2216
2217 ########## RDS Radiotext / Rass Support BEGIN
2218                 self.infobar = infobar # reference to real infobar (the one and only)
2219                 self["RdsDecoder"] = self.info["RdsDecoder"]
2220                 self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions",
2221                 {
2222                         "startRassInteractive": (self.startRassInteractive, _("View Rass interactive..."))
2223                 },-1)
2224                 self["RdsActions"].setEnabled(False)
2225                 infobar.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
2226                 self.onClose.append(self.__onClose)
2227                 self.onExecBegin.append(self.__onExecBegin)
2228                 self.onExecEnd.append(self.__onExecEnd)
2229
2230         def __onClose(self):
2231                 lastservice = eServiceReference(config.tv.lastservice.value)
2232                 self.session.nav.playService(lastservice)
2233
2234         def startRassInteractive(self):
2235                 self.info.hide();
2236                 self.infobar.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
2237
2238         def RassInteractiveClosed(self):
2239                 self.info.show()
2240                 self.infobar.rass_interactive = None
2241                 self.infobar.RassSlidePicChanged()
2242
2243         def RassInteractivePossibilityChanged(self, state):
2244                 self["RdsActions"].setEnabled(state)
2245 ########## RDS Radiotext / Rass Support END
2246
2247         def __onExecBegin(self):
2248                 self.info.show()
2249
2250         def __onExecEnd(self):
2251                 self.info.hide()
2252
2253         def cancel(self):
2254                 self.infobar.rds_display.onRassInteractivePossibilityChanged.remove(self.RassInteractivePossibilityChanged)
2255                 self.info.hide()
2256                 #set previous tv service
2257                 self.close(None)
2258
2259         def __evServiceStart(self):
2260                 service = self.session.nav.getCurrentService()
2261                 if service:
2262                         info = service.info()
2263                         if info:
2264                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
2265                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
2266
2267         def __evServiceEnd(self):
2268                 self.servicelist.setPlayableIgnoreService(eServiceReference())
2269
2270         def saveRoot(self):
2271                 path = ''
2272                 for i in self.servicePathRadio:
2273                         path += i.toString()
2274                         path += ';'
2275                 if path and path != config.radio.lastroot.value:
2276                         config.radio.lastroot.value = path
2277                         config.radio.lastroot.save()
2278
2279         def restoreRoot(self):
2280                 tmp = [x for x in config.radio.lastroot.value.split(';') if x != '']
2281                 current = [x.toString() for x in self.servicePath]
2282                 if tmp != current or self.rootChanged:
2283                         cnt = 0
2284                         for i in tmp:
2285                                 self.servicePathRadio.append(eServiceReference(i))
2286                                 cnt += 1
2287                         if cnt:
2288                                 path = self.servicePathRadio.pop()
2289                                 self.enterPath(path)
2290                         else:
2291                                 self.showFavourites()
2292                                 self.saveRoot()
2293                         self.rootChanged = False
2294
2295         def preEnterPath(self, refstr):
2296                 if self.servicePathRadio and self.servicePathRadio[0] != eServiceReference(refstr):
2297                         pathstr = config.radio.lastroot.value
2298                         if pathstr is not None and refstr in pathstr:
2299                                 self.restoreRoot()
2300                                 lastservice = eServiceReference(config.radio.lastservice.value)
2301                                 if lastservice.valid():
2302                                         self.setCurrentSelection(lastservice)
2303                                 return True
2304                 return False
2305
2306         def onCreate(self):
2307                 self.setRadioMode()
2308                 self.restoreRoot()
2309                 lastservice = eServiceReference(config.radio.lastservice.value)
2310                 if lastservice.valid():
2311                         self.servicelist.setCurrent(lastservice)
2312                         self.session.nav.playService(lastservice)
2313                 else:
2314                         self.session.nav.stopService()
2315                 self.info.show()
2316
2317         def channelSelected(self, doClose=False): # just return selected service
2318                 ref = self.getCurrentSelection()
2319                 if self.movemode:
2320                         self.toggleMoveMarked()
2321                 elif (ref.flags & eServiceReference.flagDirectory) == eServiceReference.flagDirectory:
2322                         self.enterPath(ref)
2323                         self.gotoCurrentServiceOrProvider(ref)
2324                 elif self.bouquet_mark_edit != OFF:
2325                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
2326                                 self.doMark()
2327                 elif not (ref.flags & eServiceReference.isMarker): # no marker
2328                         cur_root = self.getRoot()
2329                         if not cur_root or not (cur_root.flags & eServiceReference.isGroup):
2330                                 playingref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
2331                                 if playingref is None or playingref != ref:
2332                                         self.session.nav.playService(ref)
2333                                         config.radio.lastservice.value = ref.toString()
2334                                         config.radio.lastservice.save()
2335                                 self.saveRoot()
2336
2337         def zapBack(self):
2338                 self.channelSelected()
2339
2340 class SimpleChannelSelection(ChannelSelectionBase):
2341         def __init__(self, session, title, currentBouquet=False):
2342                 ChannelSelectionBase.__init__(self, session)
2343                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
2344                         {
2345                                 "cancel": self.close,
2346                                 "ok": self.channelSelected,
2347                                 "keyRadio": self.setModeRadio,
2348                                 "keyTV": self.setModeTv,
2349                         })
2350                 self.bouquet_mark_edit = OFF
2351                 self.title = title
2352                 self.currentBouquet = currentBouquet
2353                 self.onLayoutFinish.append(self.layoutFinished)
2354
2355         def layoutFinished(self):
2356                 self.setModeTv()
2357                 if self.currentBouquet:
2358                         ref = Screens.InfoBar.InfoBar.instance.servicelist.getRoot()
2359                         if ref:
2360                                 self.enterPath(ref)
2361                                 self.gotoCurrentServiceOrProvider(ref)
2362
2363         def saveRoot(self):
2364                 pass
2365
2366         def keyRecord(self):
2367                 return 0
2368
2369         def channelSelected(self): # just return selected service
2370                 ref = self.getCurrentSelection()
2371                 if (ref.flags & eServiceReference.flagDirectory) == eServiceReference.flagDirectory:
2372                         self.enterPath(ref)
2373                         self.gotoCurrentServiceOrProvider(ref)
2374                 elif not (ref.flags & eServiceReference.isMarker):
2375                         ref = self.getCurrentSelection()
2376                         self.close(ref)
2377
2378         def setModeTv(self):
2379                 self.setTvMode()
2380                 self.showFavourites()
2381
2382         def setModeRadio(self):
2383                 self.setRadioMode()
2384                 self.showFavourites()