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