enigma2 (20120321 rel32 -> 20120327 rel32)
[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, 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_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.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
767                 self["ChannelSelectBaseActions"] = NumberActionMap(["ChannelSelectBaseActions", "NumberActions", "InputAsciiActions"],
768                         {
769                                 "showFavourites": self.showFavourites,
770                                 "showAllServices": self.showAllServices,
771                                 "showProviders": self.showProviders,
772                                 "showSatellites": self.showSatellites,
773                                 "nextBouquet": self.nextBouquet,
774                                 "prevBouquet": self.prevBouquet,
775                                 "nextMarker": self.nextMarker,
776                                 "prevMarker": self.prevMarker,
777                                 "gotAsciiCode": self.keyAsciiCode,
778                                 "1": self.keyNumberGlobal,
779                                 "2": self.keyNumberGlobal,
780                                 "3": self.keyNumberGlobal,
781                                 "4": self.keyNumberGlobal,
782                                 "5": self.keyNumberGlobal,
783                                 "6": self.keyNumberGlobal,
784                                 "7": self.keyNumberGlobal,
785                                 "8": self.keyNumberGlobal,
786                                 "9": self.keyNumberGlobal,
787                                 "0": self.keyNumber0
788                         })
789                 self.recallBouquetMode()
790
791         def getBouquetNumOffset(self, bouquet):
792                 if not config.usage.multibouquet.value:
793                         return 0
794                 str = bouquet.toString()
795                 offsetCount = 0
796                 if not self.bouquetNumOffsetCache.has_key(str):
797                         serviceHandler = eServiceCenter.getInstance()
798                         bouquetlist = serviceHandler.list(self.bouquet_root)
799                         if not bouquetlist is None:
800                                 while True:
801                                         bouquetIterator = bouquetlist.getNext()
802                                         if not bouquetIterator.valid(): #end of list
803                                                 break
804                                         self.bouquetNumOffsetCache[bouquetIterator.toString()]=offsetCount
805                                         if not (bouquetIterator.flags & eServiceReference.isDirectory):
806                                                 continue
807                                         servicelist = serviceHandler.list(bouquetIterator)
808                                         if not servicelist is None:
809                                                 while True:
810                                                         serviceIterator = servicelist.getNext()
811                                                         if not serviceIterator.valid(): #check if end of list
812                                                                 break
813                                                         playable = not (serviceIterator.flags & (eServiceReference.isDirectory|eServiceReference.isMarker))
814                                                         if playable:
815                                                                 offsetCount += 1
816                 return self.bouquetNumOffsetCache.get(str, offsetCount)
817
818         def recallBouquetMode(self):
819                 if self.mode == MODE_TV:
820                         self.service_types = service_types_tv
821                         if config.usage.multibouquet.value:
822                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.tv" ORDER BY bouquet'
823                         else:
824                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)
825                 else:
826                         self.service_types = service_types_radio
827                         if config.usage.multibouquet.value:
828                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.radio" ORDER BY bouquet'
829                         else:
830                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(self.service_types)
831                 self.bouquet_root = eServiceReference(self.bouquet_rootstr)
832
833         def setTvMode(self):
834                 self.mode = MODE_TV
835                 self.servicePath = self.servicePathTV
836                 self.recallBouquetMode()
837                 title = self.getTitle()
838                 pos = title.find(" (")
839                 if pos != -1:
840                         title = title[:pos]
841                 title += " (TV)"
842                 self.setTitle(title)
843
844         def setRadioMode(self):
845                 self.mode = MODE_RADIO
846                 self.servicePath = self.servicePathRadio
847                 self.recallBouquetMode()
848                 title = self.getTitle()
849                 pos = title.find(" (")
850                 if pos != -1:
851                         title = title[:pos]
852                 title += " (Radio)"
853                 self.setTitle(title)
854
855         def setRoot(self, root, justSet=False):
856                 path = root.getPath()
857                 inBouquetRootList = path.find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
858                 pos = path.find('FROM BOUQUET')
859                 isBouquet = (pos != -1) and (root.flags & eServiceReference.isDirectory)
860                 if not inBouquetRootList and isBouquet:
861                         self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
862                         self.servicelist.setNumberOffset(self.getBouquetNumOffset(root))
863                 else:
864                         self.servicelist.setMode(ServiceList.MODE_NORMAL)
865                 self.servicelist.setRoot(root, justSet)
866                 self.rootChanged = True
867                 self.buildTitleString()
868
869         def removeModeStr(self, str):
870                 if self.mode == MODE_TV:
871                         pos = str.find(' (TV)')
872                 else:
873                         pos = str.find(' (Radio)')
874                 if pos != -1:
875                         return str[:pos]
876                 return str
877
878         def getServiceName(self, ref):
879                 str = self.removeModeStr(ServiceReference(ref).getServiceName())
880                 if not str:
881                         pathstr = ref.getPath()
882                         if 'FROM PROVIDERS' in pathstr:
883                                 return _("Provider")
884                         if 'FROM SATELLITES' in pathstr:
885                                 return _("Satellites")
886                         if ') ORDER BY name' in pathstr:
887                                 return _("All")
888                 return str
889
890         def buildTitleString(self):
891                 titleStr = self.getTitle()
892                 pos = titleStr.find(']')
893                 if pos == -1:
894                         pos = titleStr.find(')')
895                 if pos != -1:
896                         titleStr = titleStr[:pos+1]
897                         Len = len(self.servicePath)
898                         if Len > 0:
899                                 base_ref = self.servicePath[0]
900                                 if Len > 1:
901                                         end_ref = self.servicePath[Len-1]
902                                 else:
903                                         end_ref = None
904                                 nameStr = self.getServiceName(base_ref)
905                                 titleStr += ' ' + nameStr
906                                 if end_ref is not None:
907                                         if Len > 2:
908                                                 titleStr += '/../'
909                                         else:
910                                                 titleStr += '/'
911                                         nameStr = self.getServiceName(end_ref)
912                                         titleStr += nameStr
913                                 self.setTitle(titleStr)
914
915         def moveUp(self):
916                 self.servicelist.moveUp()
917
918         def moveDown(self):
919                 self.servicelist.moveDown()
920
921         def clearPath(self):
922                 del self.servicePath[:]
923
924         def enterPath(self, ref, justSet=False):
925                 self.servicePath.append(ref)
926                 self.setRoot(ref, justSet)
927
928         def pathUp(self, justSet=False):
929                 prev = self.servicePath.pop()
930                 if self.servicePath:
931                         current = self.servicePath[-1]
932                         self.setRoot(current, justSet)
933                         if not justSet:
934                                 self.setCurrentSelection(prev)
935                 return prev
936
937         def isBasePathEqual(self, ref):
938                 if len(self.servicePath) > 1 and self.servicePath[0] == ref:
939                         return True
940                 return False
941
942         def isPrevPathEqual(self, ref):
943                 length = len(self.servicePath)
944                 if length > 1 and self.servicePath[length-2] == ref:
945                         return True
946                 return False
947
948         def preEnterPath(self, refstr):
949                 return False
950
951         def showAllServices(self):
952                 if not self.pathChangeDisabled:
953                         refstr = '%s ORDER BY name'%(self.service_types)
954                         if not self.preEnterPath(refstr):
955                                 ref = eServiceReference(refstr)
956                                 currentRoot = self.getRoot()
957                                 if currentRoot is None or currentRoot != ref:
958                                         self.clearPath()
959                                         self.enterPath(ref)
960
961         def showSatellites(self):
962                 if not self.pathChangeDisabled:
963                         refstr = '%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)
964                         if not self.preEnterPath(refstr):
965                                 ref = eServiceReference(refstr)
966                                 justSet=False
967                                 prev = None
968
969                                 if self.isBasePathEqual(ref):
970                                         if self.isPrevPathEqual(ref):
971                                                 justSet=True
972                                         prev = self.pathUp(justSet)
973                                 else:
974                                         currentRoot = self.getRoot()
975                                         if currentRoot is None or currentRoot != ref:
976                                                 justSet=True
977                                                 self.clearPath()
978                                                 self.enterPath(ref, True)
979                                 if justSet:
980                                         serviceHandler = eServiceCenter.getInstance()
981                                         servicelist = serviceHandler.list(ref)
982                                         if not servicelist is None:
983                                                 while True:
984                                                         service = servicelist.getNext()
985                                                         if not service.valid(): #check if end of list
986                                                                 break
987                                                         unsigned_orbpos = service.getUnsignedData(4) >> 16
988                                                         orbpos = service.getData(4) >> 16
989                                                         if orbpos < 0:
990                                                                 orbpos += 3600
991                                                         if service.getPath().find("FROM PROVIDER") != -1:
992                                                                 service_type = _("Providers")
993                                                         elif service.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
994                                                                 service_type = _("New")
995                                                         elif service.getPath().find("numCAIDs") != -1:
996                                                                 service_type = _("Services") + " FTA"
997                                                         else:
998                                                                 service_type = _("Services")
999                                                         try:
1000                                                                 # why we need this cast?
1001                                                                 service_name = str(nimmanager.getSatDescription(orbpos))
1002                                                         except:
1003                                                                 if unsigned_orbpos == 0xFFFF: #Cable
1004                                                                         service_name = _("Cable")
1005                                                                 elif unsigned_orbpos == 0xEEEE: #Terrestrial
1006                                                                         service_name = _("Terrestrial")
1007                                                                 else:
1008                                                                         if orbpos > 1800: # west
1009                                                                                 orbpos = 3600 - orbpos
1010                                                                                 h = _("W")
1011                                                                         else:
1012                                                                                 h = _("E")
1013                                                                         service_name = ("%d.%d" + h) % (orbpos / 10, orbpos % 10)
1014                                                         service.setName("%s - %s" % (service_name, service_type))
1015                                                         self.servicelist.addService(service)
1016                                                 cur_ref = self.session.nav.getCurrentlyPlayingServiceReference()
1017                                                 if cur_ref:
1018                                                         pos = self.service_types.rfind(':')
1019                                                         refstr = '%s (channelID == %08x%04x%04x) && %s ORDER BY name' %(self.service_types[:pos+1],
1020                                                                 cur_ref.getUnsignedData(4), # NAMESPACE
1021                                                                 cur_ref.getUnsignedData(2), # TSID
1022                                                                 cur_ref.getUnsignedData(3), # ONID
1023                                                                 self.service_types[pos+1:])
1024                                                         ref = eServiceReference(refstr)
1025                                                         ref.setName(_("Current Transponder"))
1026                                                         self.servicelist.addService(ref)
1027                                                 self.servicelist.finishFill()
1028                                                 if prev is not None:
1029                                                         self.setCurrentSelection(prev)
1030
1031         def showProviders(self):
1032                 if not self.pathChangeDisabled:
1033                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
1034                         if not self.preEnterPath(refstr):
1035                                 ref = eServiceReference(refstr)
1036                                 if self.isBasePathEqual(ref):
1037                                         self.pathUp()
1038                                 else:
1039                                         currentRoot = self.getRoot()
1040                                         if currentRoot is None or currentRoot != ref:
1041                                                 self.clearPath()
1042                                                 self.enterPath(ref)
1043
1044         def changeBouquet(self, direction):
1045                 if not self.pathChangeDisabled:
1046                         if len(self.servicePath) > 1:
1047                                 #when enter satellite root list we must do some magic stuff..
1048                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
1049                                 if self.isBasePathEqual(ref):
1050                                         self.showSatellites()
1051                                 else:
1052                                         self.pathUp()
1053                                 if direction < 0:
1054                                         self.moveUp()
1055                                 else:
1056                                         self.moveDown()
1057                                 ref = self.getCurrentSelection()
1058                                 self.enterPath(ref)
1059
1060         def inBouquet(self):
1061                 if self.servicePath and self.servicePath[0] == self.bouquet_root:
1062                         return True
1063                 return False
1064
1065         def atBegin(self):
1066                 return self.servicelist.atBegin()
1067
1068         def atEnd(self):
1069                 return self.servicelist.atEnd()
1070
1071         def nextBouquet(self):
1072                 self.changeBouquet(+1)
1073
1074         def prevBouquet(self):
1075                 self.changeBouquet(-1)
1076
1077         def showFavourites(self):
1078                 if not self.pathChangeDisabled:
1079                         if not self.preEnterPath(self.bouquet_rootstr):
1080                                 if self.isBasePathEqual(self.bouquet_root):
1081                                         self.pathUp()
1082                                 else:
1083                                         currentRoot = self.getRoot()
1084                                         if currentRoot is None or currentRoot != self.bouquet_root:
1085                                                 self.clearPath()
1086                                                 self.enterPath(self.bouquet_root)
1087
1088         def keyNumberGlobal(self, number):
1089                 unichar = self.numericalTextInput.getKey(number)
1090                 charstr = unichar.encode("utf-8")
1091                 if len(charstr) == 1:
1092                         self.servicelist.moveToChar(charstr[0])
1093
1094         def keyAsciiCode(self):
1095                 unichar = unichr(getPrevAsciiCode())
1096                 charstr = unichar.encode("utf-8")
1097                 if len(charstr) == 1:
1098                         self.servicelist.moveToChar(charstr[0])
1099
1100         def getRoot(self):
1101                 return self.servicelist.getRoot()
1102
1103         def getCurrentSelection(self):
1104                 return self.servicelist.getCurrent()
1105
1106         def setCurrentSelection(self, service):
1107                 self.servicelist.setCurrent(service)
1108
1109         def getBouquetList(self):
1110                 bouquets = [ ]
1111                 serviceHandler = eServiceCenter.getInstance()
1112                 if config.usage.multibouquet.value:
1113                         list = serviceHandler.list(self.bouquet_root)
1114                         if list:
1115                                 while True:
1116                                         s = list.getNext()
1117                                         if not s.valid():
1118                                                 break
1119                                         if s.flags & eServiceReference.isDirectory:
1120                                                 info = serviceHandler.info(s)
1121                                                 if info:
1122                                                         bouquets.append((info.getName(s), s))
1123                                 return bouquets
1124                 else:
1125                         info = serviceHandler.info(self.bouquet_root)
1126                         if info:
1127                                 bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
1128                         return bouquets
1129                 return None
1130
1131         def keyNumber0(self, num):
1132                 if len(self.servicePath) > 1:
1133                         self.keyGoUp()
1134                 else:
1135                         self.keyNumberGlobal(num)
1136
1137         def keyGoUp(self):
1138                 if len(self.servicePath) > 1:
1139                         if self.isBasePathEqual(self.bouquet_root):
1140                                 self.showFavourites()
1141                         else:
1142                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
1143                                 if self.isBasePathEqual(ref):
1144                                         self.showSatellites()
1145                                 else:
1146                                         ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
1147                                         if self.isBasePathEqual(ref):
1148                                                 self.showProviders()
1149                                         else:
1150                                                 self.showAllServices()
1151
1152         def nextMarker(self):
1153                 self.servicelist.moveToNextMarker()
1154
1155         def prevMarker(self):
1156                 self.servicelist.moveToPrevMarker()
1157
1158 HISTORYSIZE = 20
1159
1160 #config for lastservice
1161 config.tv = ConfigSubsection()
1162 config.tv.lastservice = ConfigText()
1163 config.tv.lastroot = ConfigText()
1164 config.radio = ConfigSubsection()
1165 config.radio.lastservice = ConfigText()
1166 config.radio.lastroot = ConfigText()
1167 config.servicelist = ConfigSubsection()
1168 config.servicelist.lastmode = ConfigText(default = "tv")
1169
1170 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, SelectionEventInfo):
1171         def __init__(self, session):
1172                 ChannelSelectionBase.__init__(self,session)
1173                 ChannelSelectionEdit.__init__(self)
1174                 ChannelSelectionEPG.__init__(self)
1175                 SelectionEventInfo.__init__(self)
1176
1177                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1178                         {
1179                                 "cancel": self.cancel,
1180                                 "ok": self.channelSelected,
1181                                 "keyRadio": self.setModeRadio,
1182                                 "keyTV": self.setModeTv,
1183                         })
1184
1185                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1186                         {
1187                                 iPlayableService.evStart: self.__evServiceStart,
1188                                 iPlayableService.evEnd: self.__evServiceEnd
1189                         })
1190
1191                 self.lastChannelRootTimer = eTimer()
1192                 self.lastChannelRootTimer.callback.append(self.__onCreate)
1193                 self.lastChannelRootTimer.start(100,True)
1194
1195                 self.history_tv = [ ]
1196                 self.history_radio = [ ]
1197                 self.history = self.history_tv
1198                 self.history_pos = 0
1199
1200                 self.lastservice = config.tv.lastservice
1201                 self.lastroot = config.tv.lastroot
1202                 self.revertMode = None
1203                 config.usage.multibouquet.addNotifier(self.multibouquet_config_changed)
1204                 self.new_service_played = False
1205                 self.onExecBegin.append(self.asciiOn)
1206
1207         def asciiOn(self):
1208                 rcinput = eRCInput.getInstance()
1209                 rcinput.setKeyboardMode(rcinput.kmAscii)
1210
1211         def asciiOff(self):
1212                 rcinput = eRCInput.getInstance()
1213                 rcinput.setKeyboardMode(rcinput.kmNone)
1214
1215         def multibouquet_config_changed(self, val):
1216                 self.recallBouquetMode()
1217
1218         def __evServiceStart(self):
1219                 service = self.session.nav.getCurrentService()
1220                 if service:
1221                         info = service.info()
1222                         if info:
1223                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1224                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1225
1226         def __evServiceEnd(self):
1227                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1228
1229         def setMode(self):
1230                 self.rootChanged = True
1231                 self.restoreRoot()
1232                 lastservice=eServiceReference(self.lastservice.value)
1233                 if lastservice.valid():
1234                         self.setCurrentSelection(lastservice)
1235
1236         def setModeTv(self):
1237                 if self.revertMode is None and config.servicelist.lastmode.value == "radio":
1238                         self.revertMode = MODE_RADIO
1239                 self.history = self.history_tv
1240                 self.lastservice = config.tv.lastservice
1241                 self.lastroot = config.tv.lastroot
1242                 config.servicelist.lastmode.value = "tv"
1243                 self.setTvMode()
1244                 self.setMode()
1245
1246         def setModeRadio(self):
1247                 if self.revertMode is None and config.servicelist.lastmode.value == "tv":
1248                         self.revertMode = MODE_TV
1249                 if config.usage.e1like_radio_mode.value:
1250                         self.history = self.history_radio
1251                         self.lastservice = config.radio.lastservice
1252                         self.lastroot = config.radio.lastroot
1253                         config.servicelist.lastmode.value = "radio"
1254                         self.setRadioMode()
1255                         self.setMode()
1256
1257         def __onCreate(self):
1258                 if config.usage.e1like_radio_mode.value:
1259                         if config.servicelist.lastmode.value == "tv":
1260                                 self.setModeTv()
1261                         else:
1262                                 self.setModeRadio()
1263                 else:
1264                         self.setModeTv()
1265                 lastservice=eServiceReference(self.lastservice.value)
1266                 if lastservice.valid():
1267                         self.zap()
1268
1269         def channelSelected(self):
1270                 ref = self.getCurrentSelection()
1271                 if self.movemode:
1272                         self.toggleMoveMarked()
1273                 elif (ref.flags & 7) == 7:
1274                         self.enterPath(ref)
1275                 elif self.bouquet_mark_edit != OFF:
1276                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1277                                 self.doMark()
1278                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1279                         root = self.getRoot()
1280                         if not root or not (root.flags & eServiceReference.isGroup):
1281                                 self.zap()
1282                                 self.asciiOff()
1283                                 self.close(ref)
1284
1285         #called from infoBar and channelSelected
1286         def zap(self):
1287                 self.revertMode=None
1288                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1289                 nref = self.getCurrentSelection()
1290                 if ref is None or ref != nref:
1291                         self.new_service_played = True
1292                         self.session.nav.playService(nref)
1293                         self.saveRoot()
1294                         self.saveChannel(nref)
1295                         config.servicelist.lastmode.save()
1296                         self.addToHistory(nref)
1297
1298         def newServicePlayed(self):
1299                 ret = self.new_service_played
1300                 self.new_service_played = False
1301                 return ret
1302
1303         def addToHistory(self, ref):
1304                 if self.servicePath is not None:
1305                         tmp=self.servicePath[:]
1306                         tmp.append(ref)
1307                         try:
1308                                 del self.history[self.history_pos+1:]
1309                         except:
1310                                 pass
1311                         self.history.append(tmp)
1312                         hlen = len(self.history)
1313                         if hlen > HISTORYSIZE:
1314                                 del self.history[0]
1315                                 hlen -= 1
1316                         self.history_pos = hlen-1
1317
1318         def historyBack(self):
1319                 hlen = len(self.history)
1320                 if hlen > 1 and self.history_pos > 0:
1321                         self.history_pos -= 1
1322                         self.setHistoryPath()
1323
1324         def historyNext(self):
1325                 hlen = len(self.history)
1326                 if hlen > 1 and self.history_pos < (hlen-1):
1327                         self.history_pos += 1
1328                         self.setHistoryPath()
1329
1330         def setHistoryPath(self):
1331                 path = self.history[self.history_pos][:]
1332                 ref = path.pop()
1333                 del self.servicePath[:]
1334                 self.servicePath += path
1335                 self.saveRoot()
1336                 root = path[-1]
1337                 cur_root = self.getRoot()
1338                 if cur_root and cur_root != root:
1339                         self.setRoot(root)
1340                 self.session.nav.playService(ref)
1341                 self.setCurrentSelection(ref)
1342                 self.saveChannel(ref)
1343
1344         def saveRoot(self):
1345                 path = ''
1346                 for i in self.servicePath:
1347                         path += i.toString()
1348                         path += ';'
1349                 if path and path != self.lastroot.value:
1350                         self.lastroot.value = path
1351                         self.lastroot.save()
1352
1353         def restoreRoot(self):
1354                 tmp = [x for x in self.lastroot.value.split(';') if x != '']
1355                 current = [x.toString() for x in self.servicePath]
1356                 if tmp != current or self.rootChanged:
1357                         self.clearPath()
1358                         cnt = 0
1359                         for i in tmp:
1360                                 self.servicePath.append(eServiceReference(i))
1361                                 cnt += 1
1362                         if cnt:
1363                                 path = self.servicePath.pop()
1364                                 self.enterPath(path)
1365                         else:
1366                                 self.showFavourites()
1367                                 self.saveRoot()
1368                         self.rootChanged = False
1369
1370         def preEnterPath(self, refstr):
1371                 if self.servicePath and self.servicePath[0] != eServiceReference(refstr):
1372                         pathstr = self.lastroot.value
1373                         if pathstr is not None and pathstr.find(refstr) == 0:
1374                                 self.restoreRoot()
1375                                 lastservice=eServiceReference(self.lastservice.value)
1376                                 if lastservice.valid():
1377                                         self.setCurrentSelection(lastservice)
1378                                 return True
1379                 return False
1380
1381         def saveChannel(self, ref):
1382                 if ref is not None:
1383                         refstr = ref.toString()
1384                 else:
1385                         refstr = ""
1386                 if refstr != self.lastservice.value:
1387                         self.lastservice.value = refstr
1388                         self.lastservice.save()
1389
1390         def setCurrentServicePath(self, path):
1391                 if self.history:
1392                         self.history[self.history_pos] = path
1393                 else:
1394                         self.history.append(path)
1395                 self.setHistoryPath()
1396
1397         def getCurrentServicePath(self):
1398                 if self.history:
1399                         return self.history[self.history_pos]
1400                 return None
1401
1402         def recallPrevService(self):
1403                 hlen = len(self.history)
1404                 if hlen > 1:
1405                         if self.history_pos == hlen-1:
1406                                 tmp = self.history[self.history_pos]
1407                                 self.history[self.history_pos] = self.history[self.history_pos-1]
1408                                 self.history[self.history_pos-1] = tmp
1409                         else:
1410                                 tmp = self.history[self.history_pos+1]
1411                                 self.history[self.history_pos+1] = self.history[self.history_pos]
1412                                 self.history[self.history_pos] = tmp
1413                         self.setHistoryPath()
1414
1415         def cancel(self):
1416                 if self.revertMode is None:
1417                         self.restoreRoot()
1418                         lastservice=eServiceReference(self.lastservice.value)
1419                         if lastservice.valid() and self.getCurrentSelection() != lastservice:
1420                                 self.setCurrentSelection(lastservice)
1421                 elif self.revertMode == MODE_TV:
1422                         self.setModeTv()
1423                 elif self.revertMode == MODE_RADIO:
1424                         self.setModeRadio()
1425                 self.revertMode = None
1426                 self.asciiOff()
1427                 self.close(None)
1428
1429 class RadioInfoBar(Screen):
1430         def __init__(self, session):
1431                 Screen.__init__(self, session)
1432                 self["RdsDecoder"] = RdsDecoder(self.session.nav)
1433
1434 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, InfoBarBase):
1435         ALLOW_SUSPEND = True
1436
1437         def __init__(self, session, infobar):
1438                 ChannelSelectionBase.__init__(self, session)
1439                 ChannelSelectionEdit.__init__(self)
1440                 ChannelSelectionEPG.__init__(self)
1441                 InfoBarBase.__init__(self)
1442                 self.infobar = infobar
1443                 self.onLayoutFinish.append(self.onCreate)
1444
1445                 self.info = session.instantiateDialog(RadioInfoBar) # our simple infobar
1446
1447                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1448                         {
1449                                 "keyTV": self.cancel,
1450                                 "keyRadio": self.cancel,
1451                                 "cancel": self.cancel,
1452                                 "ok": self.channelSelected,
1453                         })
1454
1455                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1456                         {
1457                                 iPlayableService.evStart: self.__evServiceStart,
1458                                 iPlayableService.evEnd: self.__evServiceEnd
1459                         })
1460
1461 ########## RDS Radiotext / Rass Support BEGIN
1462                 self.infobar = infobar # reference to real infobar (the one and only)
1463                 self["RdsDecoder"] = self.info["RdsDecoder"]
1464                 self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions",
1465                 {
1466                         "startRassInteractive": (self.startRassInteractive, _("View Rass interactive..."))
1467                 },-1)
1468                 self["RdsActions"].setEnabled(False)
1469                 infobar.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
1470                 self.onClose.append(self.__onClose)
1471
1472         def __onClose(self):
1473                 lastservice=eServiceReference(config.tv.lastservice.value)
1474                 self.session.nav.playService(lastservice)
1475
1476         def startRassInteractive(self):
1477                 self.info.hide();
1478                 self.infobar.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
1479
1480         def RassInteractiveClosed(self):
1481                 self.info.show()
1482                 self.infobar.rass_interactive = None
1483                 self.infobar.RassSlidePicChanged()
1484
1485         def RassInteractivePossibilityChanged(self, state):
1486                 self["RdsActions"].setEnabled(state)
1487 ########## RDS Radiotext / Rass Support END
1488
1489         def cancel(self):
1490                 self.infobar.rds_display.onRassInteractivePossibilityChanged.remove(self.RassInteractivePossibilityChanged)
1491                 self.info.hide()
1492                 #set previous tv service
1493                 self.close(None)
1494
1495         def __evServiceStart(self):
1496                 service = self.session.nav.getCurrentService()
1497                 if service:
1498                         info = service.info()
1499                         if info:
1500                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1501                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1502
1503         def __evServiceEnd(self):
1504                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1505
1506         def saveRoot(self):
1507                 path = ''
1508                 for i in self.servicePathRadio:
1509                         path += i.toString()
1510                         path += ';'
1511                 if path and path != config.radio.lastroot.value:
1512                         config.radio.lastroot.value = path
1513                         config.radio.lastroot.save()
1514
1515         def restoreRoot(self):
1516                 tmp = [x for x in config.radio.lastroot.value.split(';') if x != '']
1517                 current = [x.toString() for x in self.servicePathRadio]
1518                 if tmp != current or self.rootChanged:
1519                         self.clearPath()
1520                         cnt = 0
1521                         for i in tmp:
1522                                 self.servicePathRadio.append(eServiceReference(i))
1523                                 cnt += 1
1524                         if cnt:
1525                                 path = self.servicePathRadio.pop()
1526                                 self.enterPath(path)
1527                         else:
1528                                 self.showFavourites()
1529                                 self.saveRoot()
1530                         self.rootChanged = False
1531
1532         def preEnterPath(self, refstr):
1533                 if self.servicePathRadio and self.servicePathRadio[0] != eServiceReference(refstr):
1534                         pathstr = config.radio.lastroot.value
1535                         if pathstr is not None and pathstr.find(refstr) == 0:
1536                                 self.restoreRoot()
1537                                 lastservice=eServiceReference(config.radio.lastservice.value)
1538                                 if lastservice.valid():
1539                                         self.setCurrentSelection(lastservice)
1540                                 return True
1541                 return False
1542
1543         def onCreate(self):
1544                 self.setRadioMode()
1545                 self.restoreRoot()
1546                 lastservice=eServiceReference(config.radio.lastservice.value)
1547                 if lastservice.valid():
1548                         self.servicelist.setCurrent(lastservice)
1549                         self.session.nav.playService(lastservice)
1550                 else:
1551                         self.session.nav.stopService()
1552                 self.info.show()
1553
1554         def channelSelected(self): # just return selected service
1555                 ref = self.getCurrentSelection()
1556                 if self.movemode:
1557                         self.toggleMoveMarked()
1558                 elif (ref.flags & 7) == 7:
1559                         self.enterPath(ref)
1560                 elif self.bouquet_mark_edit != OFF:
1561                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1562                                 self.doMark()
1563                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1564                         cur_root = self.getRoot()
1565                         if not cur_root or not (cur_root.flags & eServiceReference.isGroup):
1566                                 playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1567                                 if playingref is None or playingref != ref:
1568                                         self.session.nav.playService(ref)
1569                                         config.radio.lastservice.value = ref.toString()
1570                                         config.radio.lastservice.save()
1571                                 self.saveRoot()
1572
1573 class SimpleChannelSelection(ChannelSelectionBase):
1574         def __init__(self, session, title):
1575                 ChannelSelectionBase.__init__(self, session)
1576                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1577                         {
1578                                 "cancel": self.close,
1579                                 "ok": self.channelSelected,
1580                                 "keyRadio": self.setModeRadio,
1581                                 "keyTV": self.setModeTv,
1582                         })
1583                 self.title = title
1584                 self.onLayoutFinish.append(self.layoutFinished)
1585
1586         def layoutFinished(self):
1587                 self.setModeTv()
1588
1589         def channelSelected(self): # just return selected service
1590                 ref = self.getCurrentSelection()
1591                 if (ref.flags & 7) == 7:
1592                         self.enterPath(ref)
1593                 elif not (ref.flags & eServiceReference.isMarker):
1594                         ref = self.getCurrentSelection()
1595                         self.close(ref)
1596
1597         def setModeTv(self):
1598                 self.setTvMode()
1599                 self.showFavourites()
1600
1601         def setModeRadio(self):
1602                 self.setRadioMode()
1603                 self.showFavourites()