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