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