fixes bug #556
[enigma2.git] / 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 Components.SystemInfo import SystemInfo
26 from Screens.InputBox import InputBox, PinInput
27 from Screens.MessageBox import MessageBox
28 from Screens.ServiceInfo import ServiceInfo
29 profile("ChannelSelection.py 4")
30 from Screens.PictureInPicture import PictureInPicture
31 from Screens.RdsDisplay import RassInteractive
32 from ServiceReference import ServiceReference
33 from Tools.BoundFunction import boundFunction
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 and SystemInfo.get("NumVideoDecoders", 1) > 1:
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(True)
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.ref.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.openWithCallback(self.exitContext, ChannelContextMenu, self)
676                 
677         def exitContext(self, close = False):
678                 if close:
679                         self.cancel()
680
681 MODE_TV = 0
682 MODE_RADIO = 1
683
684 # type 1 = digital television service
685 # type 4 = nvod reference service (NYI)
686 # type 17 = MPEG-2 HD digital television service
687 # type 22 = advanced codec SD digital television
688 # type 24 = advanced codec SD NVOD reference service (NYI)
689 # type 25 = advanced codec HD digital television
690 # type 27 = advanced codec HD NVOD reference service (NYI)
691 # type 2 = digital radio sound service
692 # type 10 = advanced codec digital radio sound service
693
694 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)'
695 service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2) || (type == 10)'
696
697 class ChannelSelectionBase(Screen):
698         def __init__(self, session):
699                 Screen.__init__(self, session)
700
701                 self["key_red"] = Button(_("All"))
702                 self["key_green"] = Button(_("Satellites"))
703                 self["key_yellow"] = Button(_("Provider"))
704                 self["key_blue"] = Button(_("Favourites"))
705
706                 self["list"] = ServiceList()
707                 self.servicelist = self["list"]
708
709                 self.numericalTextInput = NumericalTextInput()
710                 self.numericalTextInput.setUseableChars(u'1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ')
711
712                 self.servicePathTV = [ ]
713                 self.servicePathRadio = [ ]
714                 self.servicePath = [ ]
715                 self.rootChanged = False
716
717                 self.mode = MODE_TV
718
719                 self.pathChangeDisabled = False
720
721                 self.bouquetNumOffsetCache = { }
722
723                 self["ChannelSelectBaseActions"] = NumberActionMap(["ChannelSelectBaseActions", "NumberActions", "InputAsciiActions"],
724                         {
725                                 "showFavourites": self.showFavourites,
726                                 "showAllServices": self.showAllServices,
727                                 "showProviders": self.showProviders,
728                                 "showSatellites": self.showSatellites,
729                                 "nextBouquet": self.nextBouquet,
730                                 "prevBouquet": self.prevBouquet,
731                                 "nextMarker": self.nextMarker,
732                                 "prevMarker": self.prevMarker,
733                                 "gotAsciiCode": self.keyAsciiCode,
734                                 "1": self.keyNumberGlobal,
735                                 "2": self.keyNumberGlobal,
736                                 "3": self.keyNumberGlobal,
737                                 "4": self.keyNumberGlobal,
738                                 "5": self.keyNumberGlobal,
739                                 "6": self.keyNumberGlobal,
740                                 "7": self.keyNumberGlobal,
741                                 "8": self.keyNumberGlobal,
742                                 "9": self.keyNumberGlobal,
743                                 "0": self.keyNumber0
744                         })
745                 self.recallBouquetMode()
746
747         def getBouquetNumOffset(self, bouquet):
748                 if not config.usage.multibouquet.value:
749                         return 0
750                 str = bouquet.toString()
751                 offsetCount = 0
752                 if not self.bouquetNumOffsetCache.has_key(str):
753                         serviceHandler = eServiceCenter.getInstance()
754                         bouquetlist = serviceHandler.list(self.bouquet_root)
755                         if not bouquetlist is None:
756                                 while True:
757                                         bouquetIterator = bouquetlist.getNext()
758                                         if not bouquetIterator.valid(): #end of list
759                                                 break
760                                         self.bouquetNumOffsetCache[bouquetIterator.toString()]=offsetCount
761                                         if not (bouquetIterator.flags & eServiceReference.isDirectory):
762                                                 continue
763                                         servicelist = serviceHandler.list(bouquetIterator)
764                                         if not servicelist is None:
765                                                 while True:
766                                                         serviceIterator = servicelist.getNext()
767                                                         if not serviceIterator.valid(): #check if end of list
768                                                                 break
769                                                         playable = not (serviceIterator.flags & (eServiceReference.isDirectory|eServiceReference.isMarker))
770                                                         if playable:
771                                                                 offsetCount += 1
772                 return self.bouquetNumOffsetCache.get(str, offsetCount)
773
774         def recallBouquetMode(self):
775                 if self.mode == MODE_TV:
776                         self.service_types = service_types_tv
777                         if config.usage.multibouquet.value:
778                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.tv" ORDER BY bouquet'
779                         else:
780                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)
781                 else:
782                         self.service_types = service_types_radio
783                         if config.usage.multibouquet.value:
784                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.radio" ORDER BY bouquet'
785                         else:
786                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(self.service_types)
787                 self.bouquet_root = eServiceReference(self.bouquet_rootstr)
788
789         def setTvMode(self):
790                 self.mode = MODE_TV
791                 self.servicePath = self.servicePathTV
792                 self.recallBouquetMode()
793                 title = self.getTitle()
794                 pos = title.find(" (")
795                 if pos != -1:
796                         title = title[:pos]
797                 title += " (TV)"
798                 self.setTitle(title)
799
800         def setRadioMode(self):
801                 self.mode = MODE_RADIO
802                 self.servicePath = self.servicePathRadio
803                 self.recallBouquetMode()
804                 title = self.getTitle()
805                 pos = title.find(" (")
806                 if pos != -1:
807                         title = title[:pos]
808                 title += " (Radio)"
809                 self.setTitle(title)
810
811         def setRoot(self, root, justSet=False):
812                 path = root.getPath()
813                 inBouquetRootList = path.find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
814                 pos = path.find('FROM BOUQUET')
815                 isBouquet = (pos != -1) and (root.flags & eServiceReference.isDirectory)
816                 if not inBouquetRootList and isBouquet:
817                         self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
818                         self.servicelist.setNumberOffset(self.getBouquetNumOffset(root))
819                 else:
820                         self.servicelist.setMode(ServiceList.MODE_NORMAL)
821                 self.servicelist.setRoot(root, justSet)
822                 self.rootChanged = True
823                 self.buildTitleString()
824
825         def removeModeStr(self, str):
826                 if self.mode == MODE_TV:
827                         pos = str.find(' (TV)')
828                 else:
829                         pos = str.find(' (Radio)')
830                 if pos != -1:
831                         return str[:pos]
832                 return str
833
834         def getServiceName(self, ref):
835                 str = self.removeModeStr(ServiceReference(ref).getServiceName())
836                 if not str:
837                         pathstr = ref.getPath()
838                         if 'FROM PROVIDERS' in pathstr:
839                                 return _("Provider")
840                         if 'FROM SATELLITES' in pathstr:
841                                 return _("Satellites")
842                         if ') ORDER BY name' in pathstr:
843                                 return _("All")
844                 return str
845
846         def buildTitleString(self):
847                 titleStr = self.getTitle()
848                 pos = titleStr.find(']')
849                 if pos == -1:
850                         pos = titleStr.find(')')
851                 if pos != -1:
852                         titleStr = titleStr[:pos+1]
853                         Len = len(self.servicePath)
854                         if Len > 0:
855                                 base_ref = self.servicePath[0]
856                                 if Len > 1:
857                                         end_ref = self.servicePath[Len-1]
858                                 else:
859                                         end_ref = None
860                                 nameStr = self.getServiceName(base_ref)
861                                 titleStr += ' ' + nameStr
862                                 if end_ref is not None:
863                                         if Len > 2:
864                                                 titleStr += '/../'
865                                         else:
866                                                 titleStr += '/'
867                                         nameStr = self.getServiceName(end_ref)
868                                         titleStr += nameStr
869                                 self.setTitle(titleStr)
870
871         def moveUp(self):
872                 self.servicelist.moveUp()
873
874         def moveDown(self):
875                 self.servicelist.moveDown()
876
877         def clearPath(self):
878                 del self.servicePath[:]
879
880         def enterPath(self, ref, justSet=False):
881                 self.servicePath.append(ref)
882                 self.setRoot(ref, justSet)
883
884         def pathUp(self, justSet=False):
885                 prev = self.servicePath.pop()
886                 if self.servicePath:
887                         current = self.servicePath[-1]
888                         self.setRoot(current, justSet)
889                         if not justSet:
890                                 self.setCurrentSelection(prev)
891                 return prev
892
893         def isBasePathEqual(self, ref):
894                 if len(self.servicePath) > 1 and self.servicePath[0] == ref:
895                         return True
896                 return False
897
898         def isPrevPathEqual(self, ref):
899                 length = len(self.servicePath)
900                 if length > 1 and self.servicePath[length-2] == ref:
901                         return True
902                 return False
903
904         def preEnterPath(self, refstr):
905                 return False
906
907         def showAllServices(self):
908                 if not self.pathChangeDisabled:
909                         refstr = '%s ORDER BY name'%(self.service_types)
910                         if not self.preEnterPath(refstr):
911                                 ref = eServiceReference(refstr)
912                                 currentRoot = self.getRoot()
913                                 if currentRoot is None or currentRoot != ref:
914                                         self.clearPath()
915                                         self.enterPath(ref)
916
917         def showSatellites(self):
918                 if not self.pathChangeDisabled:
919                         refstr = '%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)
920                         if not self.preEnterPath(refstr):
921                                 ref = eServiceReference(refstr)
922                                 justSet=False
923                                 prev = None
924
925                                 if self.isBasePathEqual(ref):
926                                         if self.isPrevPathEqual(ref):
927                                                 justSet=True
928                                         prev = self.pathUp(justSet)
929                                 else:
930                                         currentRoot = self.getRoot()
931                                         if currentRoot is None or currentRoot != ref:
932                                                 justSet=True
933                                                 self.clearPath()
934                                                 self.enterPath(ref, True)
935                                 if justSet:
936                                         serviceHandler = eServiceCenter.getInstance()
937                                         servicelist = serviceHandler.list(ref)
938                                         if not servicelist is None:
939                                                 while True:
940                                                         service = servicelist.getNext()
941                                                         if not service.valid(): #check if end of list
942                                                                 break
943                                                         unsigned_orbpos = service.getUnsignedData(4) >> 16
944                                                         orbpos = service.getData(4) >> 16
945                                                         if orbpos < 0:
946                                                                 orbpos += 3600
947                                                         if service.getPath().find("FROM PROVIDER") != -1:
948                                                                 service_type = _("Providers")
949                                                         elif service.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
950                                                                 service_type = _("New")
951                                                         else:
952                                                                 service_type = _("Services")
953                                                         try:
954                                                                 # why we need this cast?
955                                                                 service_name = str(nimmanager.getSatDescription(orbpos))
956                                                         except:
957                                                                 if unsigned_orbpos == 0xFFFF: #Cable
958                                                                         service_name = _("Cable")
959                                                                 elif unsigned_orbpos == 0xEEEE: #Terrestrial
960                                                                         service_name = _("Terrestrial")
961                                                                 else:
962                                                                         if orbpos > 1800: # west
963                                                                                 orbpos = 3600 - orbpos
964                                                                                 h = _("W")
965                                                                         else:
966                                                                                 h = _("E")
967                                                                         service_name = ("%d.%d" + h) % (orbpos / 10, orbpos % 10)
968                                                         service.setName("%s - %s" % (service_name, service_type))
969                                                         self.servicelist.addService(service)
970                                                 cur_ref = self.session.nav.getCurrentlyPlayingServiceReference()
971                                                 if cur_ref:
972                                                         pos = self.service_types.rfind(':')
973                                                         refstr = '%s (channelID == %08x%04x%04x) && %s ORDER BY name' %(self.service_types[:pos+1],
974                                                                 cur_ref.getUnsignedData(4), # NAMESPACE
975                                                                 cur_ref.getUnsignedData(2), # TSID
976                                                                 cur_ref.getUnsignedData(3), # ONID
977                                                                 self.service_types[pos+1:])
978                                                         ref = eServiceReference(refstr)
979                                                         ref.setName(_("Current Transponder"))
980                                                         self.servicelist.addService(ref)
981                                                 self.servicelist.finishFill()
982                                                 if prev is not None:
983                                                         self.setCurrentSelection(prev)
984
985         def showProviders(self):
986                 if not self.pathChangeDisabled:
987                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
988                         if not self.preEnterPath(refstr):
989                                 ref = eServiceReference(refstr)
990                                 if self.isBasePathEqual(ref):
991                                         self.pathUp()
992                                 else:
993                                         currentRoot = self.getRoot()
994                                         if currentRoot is None or currentRoot != ref:
995                                                 self.clearPath()
996                                                 self.enterPath(ref)
997
998         def changeBouquet(self, direction):
999                 if not self.pathChangeDisabled:
1000                         if len(self.servicePath) > 1:
1001                                 #when enter satellite root list we must do some magic stuff..
1002                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
1003                                 if self.isBasePathEqual(ref):
1004                                         self.showSatellites()
1005                                 else:
1006                                         self.pathUp()
1007                                 if direction < 0:
1008                                         self.moveUp()
1009                                 else:
1010                                         self.moveDown()
1011                                 ref = self.getCurrentSelection()
1012                                 self.enterPath(ref)
1013
1014         def inBouquet(self):
1015                 if self.servicePath and self.servicePath[0] == self.bouquet_root:
1016                         return True
1017                 return False
1018
1019         def atBegin(self):
1020                 return self.servicelist.atBegin()
1021
1022         def atEnd(self):
1023                 return self.servicelist.atEnd()
1024
1025         def nextBouquet(self):
1026                 self.changeBouquet(+1)
1027
1028         def prevBouquet(self):
1029                 self.changeBouquet(-1)
1030
1031         def showFavourites(self):
1032                 if not self.pathChangeDisabled:
1033                         if not self.preEnterPath(self.bouquet_rootstr):
1034                                 if self.isBasePathEqual(self.bouquet_root):
1035                                         self.pathUp()
1036                                 else:
1037                                         currentRoot = self.getRoot()
1038                                         if currentRoot is None or currentRoot != self.bouquet_root:
1039                                                 self.clearPath()
1040                                                 self.enterPath(self.bouquet_root)
1041
1042         def keyNumberGlobal(self, number):
1043                 unichar = self.numericalTextInput.getKey(number)
1044                 charstr = unichar.encode("utf-8")
1045                 if len(charstr) == 1:
1046                         self.servicelist.moveToChar(charstr[0])
1047
1048         def keyAsciiCode(self):
1049                 unichar = unichr(getPrevAsciiCode())
1050                 charstr = unichar.encode("utf-8")
1051                 if len(charstr) == 1:
1052                         self.servicelist.moveToChar(charstr[0])
1053
1054         def getRoot(self):
1055                 return self.servicelist.getRoot()
1056
1057         def getCurrentSelection(self):
1058                 return self.servicelist.getCurrent()
1059
1060         def setCurrentSelection(self, service):
1061                 self.servicelist.setCurrent(service)
1062
1063         def getBouquetList(self):
1064                 bouquets = [ ]
1065                 serviceHandler = eServiceCenter.getInstance()
1066                 if config.usage.multibouquet.value:
1067                         list = serviceHandler.list(self.bouquet_root)
1068                         if list:
1069                                 while True:
1070                                         s = list.getNext()
1071                                         if not s.valid():
1072                                                 break
1073                                         if s.flags & eServiceReference.isDirectory:
1074                                                 info = serviceHandler.info(s)
1075                                                 if info:
1076                                                         bouquets.append((info.getName(s), s))
1077                                 return bouquets
1078                 else:
1079                         info = serviceHandler.info(self.bouquet_root)
1080                         if info:
1081                                 bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
1082                         return bouquets
1083                 return None
1084
1085         def keyNumber0(self, num):
1086                 if len(self.servicePath) > 1:
1087                         self.keyGoUp()
1088                 else:
1089                         self.keyNumberGlobal(num)
1090
1091         def keyGoUp(self):
1092                 if len(self.servicePath) > 1:
1093                         if self.isBasePathEqual(self.bouquet_root):
1094                                 self.showFavourites()
1095                         else:
1096                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
1097                                 if self.isBasePathEqual(ref):
1098                                         self.showSatellites()
1099                                 else:
1100                                         ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
1101                                         if self.isBasePathEqual(ref):
1102                                                 self.showProviders()
1103                                         else:
1104                                                 self.showAllServices()
1105
1106         def nextMarker(self):
1107                 self.servicelist.moveToNextMarker()
1108
1109         def prevMarker(self):
1110                 self.servicelist.moveToPrevMarker()
1111
1112 HISTORYSIZE = 20
1113
1114 #config for lastservice
1115 config.tv = ConfigSubsection()
1116 config.tv.lastservice = ConfigText()
1117 config.tv.lastroot = ConfigText()
1118 config.radio = ConfigSubsection()
1119 config.radio.lastservice = ConfigText()
1120 config.radio.lastroot = ConfigText()
1121 config.servicelist = ConfigSubsection()
1122 config.servicelist.lastmode = ConfigText(default = "tv")
1123
1124 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, SelectionEventInfo):
1125         def __init__(self, session):
1126                 ChannelSelectionBase.__init__(self,session)
1127                 ChannelSelectionEdit.__init__(self)
1128                 ChannelSelectionEPG.__init__(self)
1129                 SelectionEventInfo.__init__(self)
1130
1131                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1132                         {
1133                                 "cancel": self.cancel,
1134                                 "ok": self.channelSelected,
1135                                 "keyRadio": self.setModeRadio,
1136                                 "keyTV": self.setModeTv,
1137                         })
1138
1139                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1140                         {
1141                                 iPlayableService.evStart: self.__evServiceStart,
1142                                 iPlayableService.evEnd: self.__evServiceEnd
1143                         })
1144
1145                 self.lastChannelRootTimer = eTimer()
1146                 self.lastChannelRootTimer.callback.append(self.__onCreate)
1147                 self.lastChannelRootTimer.start(100,True)
1148
1149                 self.history_tv = [ ]
1150                 self.history_radio = [ ]
1151                 self.history = self.history_tv
1152                 self.history_pos = 0
1153
1154                 self.lastservice = config.tv.lastservice
1155                 self.lastroot = config.tv.lastroot
1156                 self.revertMode = None
1157                 config.usage.multibouquet.addNotifier(self.multibouquet_config_changed)
1158                 self.new_service_played = False
1159                 self.onExecBegin.append(self.asciiOn)
1160
1161         def asciiOn(self):
1162                 rcinput = eRCInput.getInstance()
1163                 rcinput.setKeyboardMode(rcinput.kmAscii)
1164
1165         def asciiOff(self):
1166                 rcinput = eRCInput.getInstance()
1167                 rcinput.setKeyboardMode(rcinput.kmNone)
1168
1169         def multibouquet_config_changed(self, val):
1170                 self.recallBouquetMode()
1171
1172         def __evServiceStart(self):
1173                 service = self.session.nav.getCurrentService()
1174                 if service:
1175                         info = service.info()
1176                         if info:
1177                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1178                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1179
1180         def __evServiceEnd(self):
1181                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1182
1183         def setMode(self):
1184                 self.rootChanged = True
1185                 self.restoreRoot()
1186                 lastservice=eServiceReference(self.lastservice.value)
1187                 if lastservice.valid():
1188                         self.setCurrentSelection(lastservice)
1189
1190         def setModeTv(self):
1191                 if self.revertMode is None and config.servicelist.lastmode.value == "radio":
1192                         self.revertMode = MODE_RADIO
1193                 self.history = self.history_tv
1194                 self.lastservice = config.tv.lastservice
1195                 self.lastroot = config.tv.lastroot
1196                 config.servicelist.lastmode.value = "tv"
1197                 self.setTvMode()
1198                 self.setMode()
1199
1200         def setModeRadio(self):
1201                 if self.revertMode is None and config.servicelist.lastmode.value == "tv":
1202                         self.revertMode = MODE_TV
1203                 if config.usage.e1like_radio_mode.value:
1204                         self.history = self.history_radio
1205                         self.lastservice = config.radio.lastservice
1206                         self.lastroot = config.radio.lastroot
1207                         config.servicelist.lastmode.value = "radio"
1208                         self.setRadioMode()
1209                         self.setMode()
1210
1211         def __onCreate(self):
1212                 if config.usage.e1like_radio_mode.value:
1213                         if config.servicelist.lastmode.value == "tv":
1214                                 self.setModeTv()
1215                         else:
1216                                 self.setModeRadio()
1217                 else:
1218                         self.setModeTv()
1219                 lastservice=eServiceReference(self.lastservice.value)
1220                 if lastservice.valid():
1221                         self.zap()
1222
1223         def channelSelected(self):
1224                 ref = self.getCurrentSelection()
1225                 if self.movemode:
1226                         self.toggleMoveMarked()
1227                 elif (ref.flags & 7) == 7:
1228                         self.enterPath(ref)
1229                 elif self.bouquet_mark_edit != OFF:
1230                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1231                                 self.doMark()
1232                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1233                         root = self.getRoot()
1234                         if not root or not (root.flags & eServiceReference.isGroup):
1235                                 self.zap()
1236                                 self.asciiOff()
1237                                 self.close(ref)
1238
1239         #called from infoBar and channelSelected
1240         def zap(self):
1241                 self.revertMode=None
1242                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1243                 nref = self.getCurrentSelection()
1244                 if ref is None or ref != nref:
1245                         self.new_service_played = True
1246                         self.session.nav.playService(nref)
1247                         self.saveRoot()
1248                         self.saveChannel(nref)
1249                         config.servicelist.lastmode.save()
1250                         self.addToHistory(nref)
1251
1252         def newServicePlayed(self):
1253                 ret = self.new_service_played
1254                 self.new_service_played = False
1255                 return ret
1256
1257         def addToHistory(self, ref):
1258                 if self.servicePath is not None:
1259                         tmp=self.servicePath[:]
1260                         tmp.append(ref)
1261                         try:
1262                                 del self.history[self.history_pos+1:]
1263                         except:
1264                                 pass
1265                         self.history.append(tmp)
1266                         hlen = len(self.history)
1267                         if hlen > HISTORYSIZE:
1268                                 del self.history[0]
1269                                 hlen -= 1
1270                         self.history_pos = hlen-1
1271
1272         def historyBack(self):
1273                 hlen = len(self.history)
1274                 if hlen > 1 and self.history_pos > 0:
1275                         self.history_pos -= 1
1276                         self.setHistoryPath()
1277
1278         def historyNext(self):
1279                 hlen = len(self.history)
1280                 if hlen > 1 and self.history_pos < (hlen-1):
1281                         self.history_pos += 1
1282                         self.setHistoryPath()
1283
1284         def setHistoryPath(self):
1285                 path = self.history[self.history_pos][:]
1286                 ref = path.pop()
1287                 del self.servicePath[:]
1288                 self.servicePath += path
1289                 self.saveRoot()
1290                 root = path[-1]
1291                 cur_root = self.getRoot()
1292                 if cur_root and cur_root != root:
1293                         self.setRoot(root)
1294                 self.session.nav.playService(ref)
1295                 self.setCurrentSelection(ref)
1296                 self.saveChannel(ref)
1297
1298         def saveRoot(self):
1299                 path = ''
1300                 for i in self.servicePath:
1301                         path += i.toString()
1302                         path += ';'
1303                 if path and path != self.lastroot.value:
1304                         self.lastroot.value = path
1305                         self.lastroot.save()
1306
1307         def restoreRoot(self):
1308                 tmp = [x for x in self.lastroot.value.split(';') if x != '']
1309                 current = [x.toString() for x in self.servicePath]
1310                 if tmp != current or self.rootChanged:
1311                         self.clearPath()
1312                         cnt = 0
1313                         for i in tmp:
1314                                 self.servicePath.append(eServiceReference(i))
1315                                 cnt += 1
1316                         if cnt:
1317                                 path = self.servicePath.pop()
1318                                 self.enterPath(path)
1319                         else:
1320                                 self.showFavourites()
1321                                 self.saveRoot()
1322                         self.rootChanged = False
1323
1324         def preEnterPath(self, refstr):
1325                 if self.servicePath and self.servicePath[0] != eServiceReference(refstr):
1326                         pathstr = self.lastroot.value
1327                         if pathstr is not None and pathstr.find(refstr) == 0:
1328                                 self.restoreRoot()
1329                                 lastservice=eServiceReference(self.lastservice.value)
1330                                 if lastservice.valid():
1331                                         self.setCurrentSelection(lastservice)
1332                                 return True
1333                 return False
1334
1335         def saveChannel(self, ref):
1336                 if ref is not None:
1337                         refstr = ref.toString()
1338                 else:
1339                         refstr = ""
1340                 if refstr != self.lastservice.value:
1341                         self.lastservice.value = refstr
1342                         self.lastservice.save()
1343
1344         def setCurrentServicePath(self, path):
1345                 if self.history:
1346                         self.history[self.history_pos] = path
1347                 else:
1348                         self.history.append(path)
1349                 self.setHistoryPath()
1350
1351         def getCurrentServicePath(self):
1352                 if self.history:
1353                         return self.history[self.history_pos]
1354                 return None
1355
1356         def recallPrevService(self):
1357                 hlen = len(self.history)
1358                 if hlen > 1:
1359                         if self.history_pos == hlen-1:
1360                                 tmp = self.history[self.history_pos]
1361                                 self.history[self.history_pos] = self.history[self.history_pos-1]
1362                                 self.history[self.history_pos-1] = tmp
1363                         else:
1364                                 tmp = self.history[self.history_pos+1]
1365                                 self.history[self.history_pos+1] = self.history[self.history_pos]
1366                                 self.history[self.history_pos] = tmp
1367                         self.setHistoryPath()
1368
1369         def cancel(self):
1370                 if self.revertMode is None:
1371                         self.restoreRoot()
1372                         lastservice=eServiceReference(self.lastservice.value)
1373                         if lastservice.valid() and self.getCurrentSelection() != lastservice:
1374                                 self.setCurrentSelection(lastservice)
1375                 elif self.revertMode == MODE_TV:
1376                         self.setModeTv()
1377                 elif self.revertMode == MODE_RADIO:
1378                         self.setModeRadio()
1379                 self.revertMode = None
1380                 self.asciiOff()
1381                 self.close(None)
1382
1383 class RadioInfoBar(Screen):
1384         def __init__(self, session):
1385                 Screen.__init__(self, session)
1386                 self["RdsDecoder"] = RdsDecoder(self.session.nav)
1387
1388 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, InfoBarBase):
1389         ALLOW_SUSPEND = True
1390
1391         def __init__(self, session, infobar):
1392                 ChannelSelectionBase.__init__(self, session)
1393                 ChannelSelectionEdit.__init__(self)
1394                 ChannelSelectionEPG.__init__(self)
1395                 InfoBarBase.__init__(self)
1396                 self.infobar = infobar
1397                 self.onLayoutFinish.append(self.onCreate)
1398
1399                 self.info = session.instantiateDialog(RadioInfoBar) # our simple infobar
1400
1401                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1402                         {
1403                                 "keyTV": self.closeRadio,
1404                                 "keyRadio": self.closeRadio,
1405                                 "cancel": self.closeRadio,
1406                                 "ok": self.channelSelected,
1407                         })
1408
1409                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1410                         {
1411                                 iPlayableService.evStart: self.__evServiceStart,
1412                                 iPlayableService.evEnd: self.__evServiceEnd
1413                         })
1414
1415 ########## RDS Radiotext / Rass Support BEGIN
1416                 self.infobar = infobar # reference to real infobar (the one and only)
1417                 self["RdsDecoder"] = self.info["RdsDecoder"]
1418                 self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions",
1419                 {
1420                         "startRassInteractive": (self.startRassInteractive, _("View Rass interactive..."))
1421                 },-1)
1422                 self["RdsActions"].setEnabled(False)
1423                 infobar.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
1424                 self.onClose.append(self.__onClose)
1425
1426         def __onClose(self):
1427                 lastservice=eServiceReference(config.tv.lastservice.value)
1428                 self.session.nav.playService(lastservice)
1429
1430         def startRassInteractive(self):
1431                 self.info.hide();
1432                 self.infobar.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
1433
1434         def RassInteractiveClosed(self):
1435                 self.info.show()
1436                 self.infobar.rass_interactive = None
1437                 self.infobar.RassSlidePicChanged()
1438
1439         def RassInteractivePossibilityChanged(self, state):
1440                 self["RdsActions"].setEnabled(state)
1441 ########## RDS Radiotext / Rass Support END
1442
1443         def closeRadio(self):
1444                 self.infobar.rds_display.onRassInteractivePossibilityChanged.remove(self.RassInteractivePossibilityChanged)
1445                 self.info.hide()
1446                 #set previous tv service
1447                 self.close(None)
1448
1449         def __evServiceStart(self):
1450                 service = self.session.nav.getCurrentService()
1451                 if service:
1452                         info = service.info()
1453                         if info:
1454                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1455                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1456
1457         def __evServiceEnd(self):
1458                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1459
1460         def saveRoot(self):
1461                 path = ''
1462                 for i in self.servicePathRadio:
1463                         path += i.toString()
1464                         path += ';'
1465                 if path and path != config.radio.lastroot.value:
1466                         config.radio.lastroot.value = path
1467                         config.radio.lastroot.save()
1468
1469         def restoreRoot(self):
1470                 tmp = [x for x in config.radio.lastroot.value.split(';') if x != '']
1471                 current = [x.toString() for x in self.servicePath]
1472                 if tmp != current or self.rootChanged:
1473                         cnt = 0
1474                         for i in tmp:
1475                                 self.servicePathRadio.append(eServiceReference(i))
1476                                 cnt += 1
1477                         if cnt:
1478                                 path = self.servicePathRadio.pop()
1479                                 self.enterPath(path)
1480                         else:
1481                                 self.showFavourites()
1482                                 self.saveRoot()
1483                         self.rootChanged = False
1484
1485         def preEnterPath(self, refstr):
1486                 if self.servicePathRadio and self.servicePathRadio[0] != eServiceReference(refstr):
1487                         pathstr = config.radio.lastroot.value
1488                         if pathstr is not None and pathstr.find(refstr) == 0:
1489                                 self.restoreRoot()
1490                                 lastservice=eServiceReference(config.radio.lastservice.value)
1491                                 if lastservice.valid():
1492                                         self.setCurrentSelection(lastservice)
1493                                 return True
1494                 return False
1495
1496         def onCreate(self):
1497                 self.setRadioMode()
1498                 self.restoreRoot()
1499                 lastservice=eServiceReference(config.radio.lastservice.value)
1500                 if lastservice.valid():
1501                         self.servicelist.setCurrent(lastservice)
1502                         self.session.nav.playService(lastservice)
1503                 else:
1504                         self.session.nav.stopService()
1505                 self.info.show()
1506
1507         def channelSelected(self): # just return selected service
1508                 ref = self.getCurrentSelection()
1509                 if self.movemode:
1510                         self.toggleMoveMarked()
1511                 elif (ref.flags & 7) == 7:
1512                         self.enterPath(ref)
1513                 elif self.bouquet_mark_edit != OFF:
1514                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1515                                 self.doMark()
1516                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1517                         cur_root = self.getRoot()
1518                         if not cur_root or not (cur_root.flags & eServiceReference.isGroup):
1519                                 playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1520                                 if playingref is None or playingref != ref:
1521                                         self.session.nav.playService(ref)
1522                                         config.radio.lastservice.value = ref.toString()
1523                                         config.radio.lastservice.save()
1524                                 self.saveRoot()
1525
1526 class SimpleChannelSelection(ChannelSelectionBase):
1527         def __init__(self, session, title):
1528                 ChannelSelectionBase.__init__(self, session)
1529                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1530                         {
1531                                 "cancel": self.close,
1532                                 "ok": self.channelSelected,
1533                                 "keyRadio": self.setModeRadio,
1534                                 "keyTV": self.setModeTv,
1535                         })
1536                 self.title = title
1537                 self.onLayoutFinish.append(self.layoutFinished)
1538
1539         def layoutFinished(self):
1540                 self.setModeTv()
1541
1542         def channelSelected(self): # just return selected service
1543                 ref = self.getCurrentSelection()
1544                 if (ref.flags & 7) == 7:
1545                         self.enterPath(ref)
1546                 elif not (ref.flags & eServiceReference.isMarker):
1547                         ref = self.getCurrentSelection()
1548                         self.close(ref)
1549
1550         def setModeTv(self):
1551                 self.setTvMode()
1552                 self.showFavourites()
1553
1554         def setModeRadio(self):
1555                 self.setRadioMode()
1556                 self.showFavourites()