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