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