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