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