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