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