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