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