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