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