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