enigma2 20131001 (master) -> 20131112 (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:
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                         cur.setName(name)
497                         self.servicelist.addService(cur, True) # add the new entry above the current position
498                         self.servicelist.removeCurrent()
499                         if not self.servicelist.atEnd():
500                                 self.servicelist.moveUp()
501                         bouquet.removeService(cur)
502                         bouquet.addService(cur)
503                         bouquet.moveService(cur, idx)
504                         bouquet.flushChanges()
505
506         def addMarker(self, name):
507                 current = self.servicelist.getCurrent()
508                 mutableList = self.getMutableList()
509                 cnt = 0
510                 while mutableList:
511                         str = '1:64:%d:0:0:0:0:0:0:0::%s'%(cnt, name)
512                         ref = eServiceReference(str)
513                         if current and current.valid():
514                                 if not mutableList.addService(ref, current):
515                                         self.servicelist.addService(ref, True)
516                                         mutableList.flushChanges()
517                                         break
518                         elif not mutableList.addService(ref):
519                                 self.servicelist.addService(ref, True)
520                                 mutableList.flushChanges()
521                                 break
522                         cnt+=1
523
524         def addAlternativeServices(self):
525                 cur_service = ServiceReference(self.getCurrentSelection())
526                 root = self.getRoot()
527                 cur_root = root and ServiceReference(root)
528                 mutableBouquet = cur_root.list().startEdit()
529                 if mutableBouquet:
530                         name = cur_service.getServiceName()
531                         print "NAME", name
532                         if self.mode == MODE_TV:
533                                 str = '1:134:1:0:0:0:0:0:0:0:FROM BOUQUET \"alternatives.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(name))
534                         else:
535                                 str = '1:134:2:0:0:0:0:0:0:0:FROM BOUQUET \"alternatives.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(name))
536                         new_ref = ServiceReference(str)
537                         if not mutableBouquet.addService(new_ref.ref, cur_service.ref):
538                                 mutableBouquet.removeService(cur_service.ref)
539                                 mutableBouquet.flushChanges()
540                                 eDVBDB.getInstance().reloadBouquets()
541                                 mutableAlternatives = new_ref.list().startEdit()
542                                 if mutableAlternatives:
543                                         mutableAlternatives.setListName(name)
544                                         if mutableAlternatives.addService(cur_service.ref):
545                                                 print "add", cur_service.ref.toString(), "to new alternatives failed"
546                                         mutableAlternatives.flushChanges()
547                                         self.servicelist.removeCurrent()
548                                         self.servicelist.addService(new_ref.ref, True)
549                                 else:
550                                         print "get mutable list for new created alternatives failed"
551                         else:
552                                 print "add", str, "to", cur_root.getServiceName(), "failed"
553                 else:
554                         print "bouquetlist is not editable"
555
556         def addBouquet(self, bName, services):
557                 serviceHandler = eServiceCenter.getInstance()
558                 mutableBouquetList = serviceHandler.list(self.bouquet_root).startEdit()
559                 if mutableBouquetList:
560                         if self.mode == MODE_TV:
561                                 bName += " (TV)"
562                                 str = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(bName))
563                         else:
564                                 bName += " (Radio)"
565                                 str = '1:7:2:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(bName))
566                         new_bouquet_ref = eServiceReference(str)
567                         if not mutableBouquetList.addService(new_bouquet_ref):
568                                 mutableBouquetList.flushChanges()
569                                 eDVBDB.getInstance().reloadBouquets()
570                                 mutableBouquet = serviceHandler.list(new_bouquet_ref).startEdit()
571                                 if mutableBouquet:
572                                         mutableBouquet.setListName(bName)
573                                         if services is not None:
574                                                 for service in services:
575                                                         if mutableBouquet.addService(service):
576                                                                 print "add", service.toString(), "to new bouquet failed"
577                                         mutableBouquet.flushChanges()
578                                 else:
579                                         print "get mutable list for new created bouquet failed"
580                                 # do some voodoo to check if current_root is equal to bouquet_root
581                                 cur_root = self.getRoot();
582                                 str1 = cur_root and cur_root.toString()
583                                 pos1 = str1 and str1.find("FROM BOUQUET") or -1
584                                 pos2 = self.bouquet_rootstr.find("FROM BOUQUET")
585                                 if pos1 != -1 and pos2 != -1 and str1[pos1:] == self.bouquet_rootstr[pos2:]:
586                                         self.servicelist.addService(new_bouquet_ref)
587                         else:
588                                 print "add", str, "to bouquets failed"
589                 else:
590                         print "bouquetlist is not editable"
591
592         def copyCurrentToBouquetList(self):
593                 provider = ServiceReference(self.getCurrentSelection())
594                 providerName = provider.getServiceName()
595                 serviceHandler = eServiceCenter.getInstance()
596                 services = serviceHandler.list(provider.ref)
597                 self.addBouquet(providerName, services and services.getContent('R', True))
598
599         def removeAlternativeServices(self):
600                 cur_service = ServiceReference(self.getCurrentSelection())
601                 root = self.getRoot()
602                 cur_root = root and ServiceReference(root)
603                 list = cur_service.list()
604                 first_in_alternative = list and list.getNext()
605                 if first_in_alternative:
606                         edit_root = cur_root and cur_root.list().startEdit()
607                         if edit_root:
608                                 if not edit_root.addService(first_in_alternative, cur_service.ref):
609                                         self.servicelist.addService(first_in_alternative, True)
610                                         self.servicelist.setCurrent(cur_service.ref)
611                                 else:
612                                         print "couldn't add first alternative service to current root"
613                         else:
614                                 print "couldn't edit current root!!"
615                 else:
616                         print "remove empty alternative list !!"
617                 self.removeBouquet()
618                 if first_in_alternative:
619                         self.servicelist.setCurrent(first_in_alternative) 
620
621         def removeBouquet(self):
622                 refstr = self.getCurrentSelection().toString()
623                 print "removeBouquet", refstr
624                 self.bouquetNumOffsetCache = { }
625                 pos = refstr.find('FROM BOUQUET "')
626                 filename = None
627                 if pos != -1:
628                         refstr = refstr[pos+14:]
629                         pos = refstr.find('"')
630                         if pos != -1:
631                                 filename = eEnv.resolve('${sysconfdir}/enigma2/') + refstr[:pos]
632                 self.removeCurrentService()
633                 try:
634                         if filename is not None:
635                                 remove(filename)
636                 except OSError:
637                         print "error during remove of", filename
638
639 #  multiple marked entry stuff ( edit mode, later multiepg selection )
640         def startMarkedEdit(self, type):
641                 self.savedPath = self.servicePath[:]
642                 if type == EDIT_ALTERNATIVES:
643                         self.enterPath(self.getCurrentSelection())
644                 self.mutableList = self.getMutableList()
645                 # add all services from the current list to internal marked set in listboxservicecontent
646                 self.clearMarks() # this clears the internal marked set in the listboxservicecontent
647                 self.saved_title = self.getTitle()
648                 pos = self.saved_title.find(')')
649                 new_title = self.saved_title[:pos+1]
650                 if type == EDIT_ALTERNATIVES:
651                         self.bouquet_mark_edit = EDIT_ALTERNATIVES
652                         new_title += ' ' + _("[alternative edit]")
653                 else:
654                         self.bouquet_mark_edit = EDIT_BOUQUET
655                         if config.usage.multibouquet.value:
656                                 new_title += ' ' + _("[bouquet edit]")
657                         else:
658                                 new_title += ' ' + _("[favourite edit]")
659                 self.setTitle(new_title)
660                 self.__marked = self.servicelist.getRootServices()
661                 for x in self.__marked:
662                         self.servicelist.addMarked(eServiceReference(x))
663                 self.showAllServices()
664
665         def endMarkedEdit(self, abort):
666                 if not abort and self.mutableList is not None:
667                         self.bouquetNumOffsetCache = { }
668                         new_marked = set(self.servicelist.getMarked())
669                         old_marked = set(self.__marked)
670                         removed = old_marked - new_marked
671                         added = new_marked - old_marked
672                         changed = False
673                         for x in removed:
674                                 changed = True
675                                 self.mutableList.removeService(eServiceReference(x))
676                         for x in added:
677                                 changed = True
678                                 self.mutableList.addService(eServiceReference(x))
679                         if changed:
680                                 self.mutableList.flushChanges()
681                 self.__marked = []
682                 self.clearMarks()
683                 self.bouquet_mark_edit = OFF
684                 self.mutableList = None
685                 self.setTitle(self.saved_title)
686                 self.saved_title = None
687                 # self.servicePath is just a reference to servicePathTv or Radio...
688                 # so we never ever do use the asignment operator in self.servicePath
689                 del self.servicePath[:] # remove all elements
690                 self.servicePath += self.savedPath # add saved elements
691                 del self.savedPath
692                 self.setRoot(self.servicePath[-1])
693
694         def clearMarks(self):
695                 self.servicelist.clearMarks()
696
697         def doMark(self):
698                 ref = self.servicelist.getCurrent()
699                 if self.servicelist.isMarked(ref):
700                         self.servicelist.removeMarked(ref)
701                 else:
702                         self.servicelist.addMarked(ref)
703
704         def removeCurrentService(self):
705                 ref = self.servicelist.getCurrent()
706                 mutableList = self.getMutableList()
707                 if ref.valid() and mutableList is not None:
708                         if not mutableList.removeService(ref):
709                                 self.bouquetNumOffsetCache = { }
710                                 mutableList.flushChanges() #FIXME dont flush on each single removed service
711                                 self.servicelist.removeCurrent()
712
713         def addServiceToBouquet(self, dest, service=None):
714                 mutableList = self.getMutableList(dest)
715                 if not mutableList is None:
716                         if service is None: #use current selected service
717                                 service = self.servicelist.getCurrent()
718                         if not mutableList.addService(service):
719                                 self.bouquetNumOffsetCache = { }
720                                 mutableList.flushChanges()
721                                 # do some voodoo to check if current_root is equal to dest
722                                 cur_root = self.getRoot();
723                                 str1 = cur_root and cur_root.toString() or -1
724                                 str2 = dest.toString()
725                                 pos1 = str1.find("FROM BOUQUET")
726                                 pos2 = str2.find("FROM BOUQUET")
727                                 if pos1 != -1 and pos2 != -1 and str1[pos1:] == str2[pos2:]:
728                                         self.servicelist.addService(service)
729
730         def toggleMoveMode(self):
731                 if self.movemode:
732                         if self.entry_marked:
733                                 self.toggleMoveMarked() # unmark current entry
734                         self.movemode = False
735                         self.pathChangeDisabled = False # re-enable path change
736                         self.mutableList.flushChanges() # FIXME add check if changes was made
737                         self.mutableList = None
738                         self.setTitle(self.saved_title)
739                         self.saved_title = None
740                         cur_root = self.getRoot()
741                         if cur_root and cur_root == self.bouquet_root:
742                                 self.bouquetNumOffsetCache = { }
743                 else:
744                         self.mutableList = self.getMutableList()
745                         self.movemode = True
746                         self.pathChangeDisabled = True # no path change allowed in movemode
747                         self.saved_title = self.getTitle()
748                         new_title = self.saved_title
749                         pos = self.saved_title.find(')')
750                         new_title = self.saved_title[:pos+1] + ' ' + _("[move mode]") + self.saved_title[pos+1:]
751                         self.setTitle(new_title);
752
753         def handleEditCancel(self):
754                 if self.movemode: #movemode active?
755                         if self.entry_marked:
756                                 self.channelSelected() # unmark
757                         self.toggleMoveMode() # disable move mode
758                 elif self.bouquet_mark_edit != OFF:
759                         self.endMarkedEdit(True) # abort edit mode
760
761         def toggleMoveMarked(self):
762                 if self.entry_marked:
763                         self.servicelist.setCurrentMarked(False)
764                         self.entry_marked = False
765                 else:
766                         self.servicelist.setCurrentMarked(True)
767                         self.entry_marked = True
768
769         def doContext(self):
770                 self.session.openWithCallback(self.exitContext, ChannelContextMenu, self)
771
772         def exitContext(self, close = False):
773                 if close:
774                         self.cancel()
775
776 MODE_TV = 0
777 MODE_RADIO = 1
778
779 # type 1 = digital television service
780 # type 4 = nvod reference service (NYI)
781 # type 17 = MPEG-2 HD digital television service
782 # type 22 = advanced codec SD digital television
783 # type 24 = advanced codec SD NVOD reference service (NYI)
784 # type 25 = advanced codec HD digital television
785 # type 27 = advanced codec HD NVOD reference service (NYI)
786 # type 2 = digital radio sound service
787 # type 10 = advanced codec digital radio sound service
788
789 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)'
790 service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2) || (type == 10)'
791
792 class ChannelSelectionBase(Screen):
793         def __init__(self, session):
794                 Screen.__init__(self, session)
795
796                 self["key_red"] = Button(_("All"))
797                 self["key_green"] = Button(_("Satellites"))
798                 self["key_yellow"] = Button(_("Provider"))
799                 self["key_blue"] = Button(_("Favourites"))
800
801                 self["list"] = ServiceList(session)
802                 self.servicelist = self["list"]
803
804                 self.numericalTextInput = NumericalTextInput()
805                 self.numericalTextInput.setUseableChars(u'1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ')
806
807                 self.servicePathTV = [ ]
808                 self.servicePathRadio = [ ]
809                 self.servicePath = [ ]
810                 self.rootChanged = False
811
812                 self.mode = MODE_TV
813
814                 self.pathChangeDisabled = False
815
816                 self.bouquetNumOffsetCache = { }
817                 self.onRootChanged = []
818
819                 self["ChannelSelectBaseActions"] = NumberActionMap(["ChannelSelectBaseActions", "NumberActions", "InputAsciiActions"],
820                         {
821                                 "showFavourites": self.showFavourites,
822                                 "showAllServices": self.showAllServices,
823                                 "showProviders": self.showProviders,
824                                 "showSatellites": self.showSatellites,
825                                 "nextBouquet": self.nextBouquet,
826                                 "prevBouquet": self.prevBouquet,
827                                 "nextMarker": self.nextMarker,
828                                 "prevMarker": self.prevMarker,
829                                 "gotAsciiCode": self.keyAsciiCode,
830                                 "1": self.keyNumberGlobal,
831                                 "2": self.keyNumberGlobal,
832                                 "3": self.keyNumberGlobal,
833                                 "4": self.keyNumberGlobal,
834                                 "5": self.keyNumberGlobal,
835                                 "6": self.keyNumberGlobal,
836                                 "7": self.keyNumberGlobal,
837                                 "8": self.keyNumberGlobal,
838                                 "9": self.keyNumberGlobal,
839                                 "0": self.keyNumber0
840                         })
841                 self.recallBouquetMode()
842
843         def getBouquetNumOffset(self, bouquet):
844                 if not config.usage.multibouquet.value:
845                         return 0
846                 str = bouquet.toString()
847                 offsetCount = 0
848                 if not self.bouquetNumOffsetCache.has_key(str):
849                         serviceHandler = eServiceCenter.getInstance()
850                         bouquetlist = serviceHandler.list(self.bouquet_root)
851                         if not bouquetlist is None:
852                                 while True:
853                                         bouquetIterator = bouquetlist.getNext()
854                                         if not bouquetIterator.valid(): #end of list
855                                                 break
856                                         self.bouquetNumOffsetCache[bouquetIterator.toString()]=offsetCount
857                                         if not (bouquetIterator.flags & eServiceReference.isDirectory):
858                                                 continue
859                                         servicelist = serviceHandler.list(bouquetIterator)
860                                         if not servicelist is None:
861                                                 while True:
862                                                         serviceIterator = servicelist.getNext()
863                                                         if not serviceIterator.valid(): #check if end of list
864                                                                 break
865                                                         playable = not (serviceIterator.flags & (eServiceReference.isDirectory|eServiceReference.isMarker))
866                                                         if playable:
867                                                                 offsetCount += 1
868                 return self.bouquetNumOffsetCache.get(str, offsetCount)
869
870         def recallBouquetMode(self):
871                 if self.mode == MODE_TV:
872                         self.service_types = service_types_tv
873                         if config.usage.multibouquet.value:
874                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.tv" ORDER BY bouquet'
875                         else:
876                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)
877                 else:
878                         self.service_types = service_types_radio
879                         if config.usage.multibouquet.value:
880                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.radio" ORDER BY bouquet'
881                         else:
882                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(self.service_types)
883                 self.bouquet_root = eServiceReference(self.bouquet_rootstr)
884
885         def setTvMode(self):
886                 self.mode = MODE_TV
887                 self.servicePath = self.servicePathTV
888                 self.recallBouquetMode()
889                 title = self.getTitle()
890                 pos = title.find(" (")
891                 if pos != -1:
892                         title = title[:pos]
893                 title += " (TV)"
894                 self.setTitle(title)
895
896         def setRadioMode(self):
897                 self.mode = MODE_RADIO
898                 self.servicePath = self.servicePathRadio
899                 self.recallBouquetMode()
900                 title = self.getTitle()
901                 pos = title.find(" (")
902                 if pos != -1:
903                         title = title[:pos]
904                 title += " (Radio)"
905                 self.setTitle(title)
906
907         def setRoot(self, root, justSet=False):
908                 path = root.getPath()
909                 setModeFavourites = False
910
911                 serviceHandler = eServiceCenter.getInstance()
912                 list = root and serviceHandler.list(root)
913                 if list is not None:
914                         if list.startEdit():
915                                 ref = list.getNext()
916                                 setModeFavourites = not (ref.flags & eServiceReference.isDirectory)
917
918                 if setModeFavourites:
919                         self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
920                         self.servicelist.setNumberOffset(self.getBouquetNumOffset(root))
921                 else:
922                         self.servicelist.setMode(ServiceList.MODE_NORMAL)
923
924                 self.servicelist.setRoot(root, justSet)
925                 self.rootChanged = True
926                 self.buildTitleString()
927
928         def removeModeStr(self, str):
929                 if self.mode == MODE_TV:
930                         pos = str.find(' (TV)')
931                 else:
932                         pos = str.find(' (Radio)')
933                 if pos != -1:
934                         return str[:pos]
935                 return str
936
937         def getServiceName(self, ref):
938                 str = self.removeModeStr(ServiceReference(ref).getServiceName())
939                 if not str:
940                         pathstr = ref.getPath()
941                         if 'FROM PROVIDERS' in pathstr:
942                                 return _("Provider")
943                         if 'FROM SATELLITES' in pathstr:
944                                 return _("Satellites")
945                         if ') ORDER BY name' in pathstr:
946                                 return _("All")
947                 return str
948
949         def buildTitleString(self):
950                 titleStr = self.getTitle()
951                 pos = titleStr.find(']')
952                 if pos == -1:
953                         pos = titleStr.find(')')
954                 if pos != -1:
955                         titleStr = titleStr[:pos+1]
956                         Len = len(self.servicePath)
957                         if Len > 0:
958                                 base_ref = self.servicePath[0]
959                                 if Len > 1:
960                                         end_ref = self.servicePath[Len-1]
961                                 else:
962                                         end_ref = None
963                                 nameStr = self.getServiceName(base_ref)
964                                 titleStr += ' ' + nameStr
965                                 if end_ref is not None:
966                                         if Len > 2:
967                                                 titleStr += '/../'
968                                         else:
969                                                 titleStr += '/'
970                                         nameStr = self.getServiceName(end_ref)
971                                         titleStr += nameStr
972                                 self.setTitle(titleStr)
973
974         def moveUp(self):
975                 self.servicelist.moveUp()
976
977         def moveDown(self):
978                 self.servicelist.moveDown()
979
980         def clearPath(self):
981                 del self.servicePath[:]
982
983         def enterPath(self, ref, justSet=False):
984                 self.servicePath.append(ref)
985                 self.setRoot(ref, justSet)
986                 for fnc in self.onRootChanged:
987                         fnc(ref)
988
989         def pathUp(self, justSet=False):
990                 prev = self.servicePath.pop()
991                 if self.servicePath:
992                         current = self.servicePath[-1]
993                         self.setRoot(current, justSet)
994                         if not justSet:
995                                 self.setCurrentSelection(prev)
996                 return prev
997
998         def isBasePathEqual(self, ref):
999                 if len(self.servicePath) > 1 and self.servicePath[0] == ref:
1000                         return True
1001                 return False
1002
1003         def isPrevPathEqual(self, ref):
1004                 length = len(self.servicePath)
1005                 if length > 1 and self.servicePath[length-2] == ref:
1006                         return True
1007                 return False
1008
1009         def preEnterPath(self, refstr):
1010                 return False
1011
1012         def showAllServices(self):
1013                 if not self.pathChangeDisabled:
1014                         refstr = '%s ORDER BY name'%(self.service_types)
1015                         if not self.preEnterPath(refstr):
1016                                 ref = eServiceReference(refstr)
1017                                 currentRoot = self.getRoot()
1018                                 if currentRoot is None or currentRoot != ref:
1019                                         self.clearPath()
1020                                         self.enterPath(ref)
1021
1022         def showSatellites(self):
1023                 if not self.pathChangeDisabled:
1024                         refstr = '%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)
1025                         if not self.preEnterPath(refstr):
1026                                 ref = eServiceReference(refstr)
1027                                 justSet=False
1028                                 prev = None
1029
1030                                 if self.isBasePathEqual(ref):
1031                                         if self.isPrevPathEqual(ref):
1032                                                 justSet=True
1033                                         prev = self.pathUp(justSet)
1034                                 else:
1035                                         currentRoot = self.getRoot()
1036                                         if currentRoot is None or currentRoot != ref:
1037                                                 justSet=True
1038                                                 self.clearPath()
1039                                                 self.enterPath(ref, True)
1040                                 if justSet:
1041                                         serviceHandler = eServiceCenter.getInstance()
1042                                         servicelist = serviceHandler.list(ref)
1043                                         if not servicelist is None:
1044                                                 self.servicelist.setMode(self.servicelist.MODE_NORMAL)
1045                                                 while True:
1046                                                         service = servicelist.getNext()
1047                                                         if not service.valid(): #check if end of list
1048                                                                 break
1049                                                         unsigned_orbpos = service.getUnsignedData(4) >> 16
1050                                                         orbpos = service.getData(4) >> 16
1051                                                         if orbpos < 0:
1052                                                                 orbpos += 3600
1053                                                         if service.getPath().find("FROM PROVIDER") != -1:
1054                                                                 service_type = _("Providers")
1055                                                         elif service.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
1056                                                                 service_type = _("New")
1057                                                         elif service.getPath().find("numCAIDs") != -1:
1058                                                                 service_type = _("Services") + " FTA"
1059                                                         else:
1060                                                                 service_type = _("Services")
1061                                                         try:
1062                                                                 # why we need this cast?
1063                                                                 service_name = str(nimmanager.getSatDescription(orbpos))
1064                                                         except:
1065                                                                 if unsigned_orbpos == 0xFFFF: #Cable
1066                                                                         service_name = _("Cable")
1067                                                                 elif unsigned_orbpos == 0xEEEE: #Terrestrial
1068                                                                         service_name = _("Terrestrial")
1069                                                                 else:
1070                                                                         if orbpos > 1800: # west
1071                                                                                 orbpos = 3600 - orbpos
1072                                                                                 h = _("W")
1073                                                                         else:
1074                                                                                 h = _("E")
1075                                                                         service_name = ("%d.%d" + h) % (orbpos / 10, orbpos % 10)
1076                                                         service.setName("%s - %s" % (service_name, service_type))
1077                                                         self.servicelist.addService(service)
1078                                                 self.servicelist.finishFill()
1079                                                 cur_ref = self.session.nav.getCurrentlyPlayingServiceReference()
1080                                                 if cur_ref:
1081                                                         pos = self.service_types.rfind(':')
1082                                                         refstr = '%s (channelID == %08x%04x%04x) && %s ORDER BY name' %(self.service_types[:pos+1],
1083                                                                 cur_ref.getUnsignedData(4), # NAMESPACE
1084                                                                 cur_ref.getUnsignedData(2), # TSID
1085                                                                 cur_ref.getUnsignedData(3), # ONID
1086                                                                 self.service_types[pos+1:])
1087                                                         ref = eServiceReference(refstr)
1088                                                         ref.flags |= eServiceReference.sort1 # needed for sort
1089                                                         ref.setName(_("Current Transponder"))
1090                                                         self.servicelist.addService(ref, True)
1091                                                         self.servicelist.moveUp()
1092                                                 if prev is not None:
1093                                                         self.setCurrentSelection(prev)
1094
1095         def showProviders(self):
1096                 if not self.pathChangeDisabled:
1097                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
1098                         if not self.preEnterPath(refstr):
1099                                 ref = eServiceReference(refstr)
1100                                 if self.isBasePathEqual(ref):
1101                                         self.pathUp()
1102                                 else:
1103                                         currentRoot = self.getRoot()
1104                                         if currentRoot is None or currentRoot != ref:
1105                                                 self.clearPath()
1106                                                 self.enterPath(ref)
1107
1108         def changeBouquet(self, direction):
1109                 if not self.pathChangeDisabled:
1110                         if len(self.servicePath) > 1:
1111                                 #when enter satellite root list we must do some magic stuff..
1112                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
1113                                 if self.isBasePathEqual(ref):
1114                                         self.showSatellites()
1115                                 else:
1116                                         self.pathUp()
1117                                 if direction < 0:
1118                                         self.moveUp()
1119                                 else:
1120                                         self.moveDown()
1121                                 ref = self.getCurrentSelection()
1122                                 self.enterPath(ref)
1123
1124         def inBouquet(self):
1125                 if self.servicePath and self.servicePath[0] == self.bouquet_root:
1126                         return True
1127                 return False
1128
1129         def atBegin(self):
1130                 return self.servicelist.atBegin()
1131
1132         def atEnd(self):
1133                 return self.servicelist.atEnd()
1134
1135         def nextBouquet(self):
1136                 self.changeBouquet(+1)
1137
1138         def prevBouquet(self):
1139                 self.changeBouquet(-1)
1140
1141         def showFavourites(self):
1142                 if not self.pathChangeDisabled:
1143                         if not self.preEnterPath(self.bouquet_rootstr):
1144                                 if self.isBasePathEqual(self.bouquet_root):
1145                                         self.pathUp()
1146                                 else:
1147                                         currentRoot = self.getRoot()
1148                                         if currentRoot is None or currentRoot != self.bouquet_root:
1149                                                 self.clearPath()
1150                                                 self.enterPath(self.bouquet_root)
1151
1152         def keyNumberGlobal(self, number):
1153                 unichar = self.numericalTextInput.getKey(number)
1154                 charstr = unichar.encode("utf-8")
1155                 if len(charstr) == 1:
1156                         self.servicelist.moveToChar(charstr[0])
1157
1158         def keyAsciiCode(self):
1159                 unichar = unichr(getPrevAsciiCode())
1160                 charstr = unichar.encode("utf-8")
1161                 if len(charstr) == 1:
1162                         self.servicelist.moveToChar(charstr[0])
1163
1164         def getRoot(self):
1165                 return self.servicelist.getRoot()
1166
1167         def getCurrentSelection(self):
1168                 return self.servicelist.getCurrent()
1169
1170         def setCurrentSelection(self, service):
1171                 self.servicelist.setCurrent(service)
1172
1173         def getBouquetList(self):
1174                 bouquets = [ ]
1175                 serviceHandler = eServiceCenter.getInstance()
1176                 if config.usage.multibouquet.value:
1177                         list = serviceHandler.list(self.bouquet_root)
1178                         if list:
1179                                 while True:
1180                                         s = list.getNext()
1181                                         if not s.valid():
1182                                                 break
1183                                         if s.flags & eServiceReference.isDirectory:
1184                                                 info = serviceHandler.info(s)
1185                                                 if info:
1186                                                         bouquets.append((info.getName(s), s))
1187                                 return bouquets
1188                 else:
1189                         info = serviceHandler.info(self.bouquet_root)
1190                         if info:
1191                                 bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
1192                         return bouquets
1193                 return None
1194
1195         def keyNumber0(self, num):
1196                 if len(self.servicePath) > 1:
1197                         self.keyGoUp()
1198                 else:
1199                         self.keyNumberGlobal(num)
1200
1201         def keyGoUp(self):
1202                 if len(self.servicePath) > 1:
1203                         if self.isBasePathEqual(self.bouquet_root):
1204                                 self.showFavourites()
1205                         else:
1206                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
1207                                 if self.isBasePathEqual(ref):
1208                                         self.showSatellites()
1209                                 else:
1210                                         ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
1211                                         if self.isBasePathEqual(ref):
1212                                                 self.showProviders()
1213                                         else:
1214                                                 self.showAllServices()
1215
1216         def nextMarker(self):
1217                 self.servicelist.moveToNextMarker()
1218
1219         def prevMarker(self):
1220                 self.servicelist.moveToPrevMarker()
1221
1222 HISTORYSIZE = 20
1223
1224 #config for lastservice
1225 config.tv = ConfigSubsection()
1226 config.tv.lastservice = ConfigText()
1227 config.tv.lastroot = ConfigText()
1228 config.radio = ConfigSubsection()
1229 config.radio.lastservice = ConfigText()
1230 config.radio.lastroot = ConfigText()
1231 config.servicelist = ConfigSubsection()
1232 config.servicelist.lastmode = ConfigText(default = "tv")
1233
1234 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, SelectionEventInfo):
1235         def __init__(self, session):
1236                 ChannelSelectionBase.__init__(self,session)
1237                 ChannelSelectionEdit.__init__(self)
1238                 ChannelSelectionEPG.__init__(self)
1239                 SelectionEventInfo.__init__(self)
1240
1241                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1242                         {
1243                                 "cancel": self.cancel,
1244                                 "ok": self.channelSelected,
1245                                 "keyRadio": self.setModeRadio,
1246                                 "keyTV": self.setModeTv,
1247                         })
1248
1249                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1250                         {
1251                                 iPlayableService.evStart: self.__evServiceStart,
1252                                 iPlayableService.evEnd: self.__evServiceEnd
1253                         })
1254
1255                 self.lastChannelRootTimer = eTimer()
1256                 self.lastChannelRootTimer.callback.append(self.__onCreate)
1257                 self.lastChannelRootTimer.start(100,True)
1258
1259                 self.history_tv = [ ]
1260                 self.history_radio = [ ]
1261                 self.history = self.history_tv
1262                 self.history_pos = 0
1263
1264                 self.lastservice = config.tv.lastservice
1265                 self.lastroot = config.tv.lastroot
1266                 self.revertMode = None
1267                 config.usage.multibouquet.addNotifier(self.multibouquet_config_changed)
1268                 self.new_service_played = False
1269
1270         def multibouquet_config_changed(self, val):
1271                 self.recallBouquetMode()
1272
1273         def __evServiceStart(self):
1274                 service = self.session.nav.getCurrentService()
1275                 if service:
1276                         info = service.info()
1277                         if info:
1278                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1279                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1280
1281         def __evServiceEnd(self):
1282                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1283
1284         def setMode(self):
1285                 self.rootChanged = True
1286                 self.restoreRoot()
1287                 lastservice=eServiceReference(self.lastservice.value)
1288                 if lastservice.valid():
1289                         self.setCurrentSelection(lastservice)
1290
1291         def setModeTv(self):
1292                 if self.revertMode is None and config.servicelist.lastmode.value == "radio":
1293                         self.revertMode = MODE_RADIO
1294                 self.history = self.history_tv
1295                 self.lastservice = config.tv.lastservice
1296                 self.lastroot = config.tv.lastroot
1297                 config.servicelist.lastmode.value = "tv"
1298                 self.setTvMode()
1299                 self.setMode()
1300
1301         def setModeRadio(self):
1302                 if self.revertMode is None and config.servicelist.lastmode.value == "tv":
1303                         self.revertMode = MODE_TV
1304                 if config.usage.e1like_radio_mode.value:
1305                         self.history = self.history_radio
1306                         self.lastservice = config.radio.lastservice
1307                         self.lastroot = config.radio.lastroot
1308                         config.servicelist.lastmode.value = "radio"
1309                         self.setRadioMode()
1310                         self.setMode()
1311
1312         def __onCreate(self):
1313                 if config.usage.e1like_radio_mode.value:
1314                         if config.servicelist.lastmode.value == "tv":
1315                                 self.setModeTv()
1316                         else:
1317                                 self.setModeRadio()
1318                 else:
1319                         self.setModeTv()
1320                 lastservice=eServiceReference(self.lastservice.value)
1321                 if lastservice.valid():
1322                         if not Screens.Standby.inStandby:
1323                                 self.zap()
1324                         else:
1325                                 Screens.Standby.inStandby.onClose.append(self.zap)
1326
1327         def channelSelected(self):
1328                 ref = self.getCurrentSelection()
1329                 if self.movemode:
1330                         self.toggleMoveMarked()
1331                 elif (ref.flags & 7) == 7:
1332                         self.enterPath(ref)
1333                 elif self.bouquet_mark_edit != OFF:
1334                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1335                                 self.doMark()
1336                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1337                         root = self.getRoot()
1338                         if not root or not (root.flags & eServiceReference.isGroup):
1339                                 self.zap()
1340                                 self.close(ref)
1341
1342         #called from infoBar and channelSelected
1343         def zap(self):
1344                 self.revertMode=None
1345                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1346                 nref = self.getCurrentSelection()
1347                 if ref is None or ref != nref:
1348                         self.new_service_played = True
1349                         self.session.nav.playService(nref)
1350                         self.saveRoot()
1351                         self.saveChannel(nref)
1352                         config.servicelist.lastmode.save()
1353                         self.addToHistory(nref)
1354
1355         def newServicePlayed(self):
1356                 ret = self.new_service_played
1357                 self.new_service_played = False
1358                 return ret
1359
1360         def addToHistory(self, ref):
1361                 if self.servicePath is not None:
1362                         tmp=self.servicePath[:]
1363                         tmp.append(ref)
1364                         try:
1365                                 del self.history[self.history_pos+1:]
1366                         except:
1367                                 pass
1368                         self.history.append(tmp)
1369                         hlen = len(self.history)
1370                         if hlen > HISTORYSIZE:
1371                                 del self.history[0]
1372                                 hlen -= 1
1373                         self.history_pos = hlen-1
1374
1375         def historyBack(self):
1376                 hlen = len(self.history)
1377                 if hlen > 1 and self.history_pos > 0:
1378                         self.history_pos -= 1
1379                         self.setHistoryPath()
1380
1381         def historyNext(self):
1382                 hlen = len(self.history)
1383                 if hlen > 1 and self.history_pos < (hlen-1):
1384                         self.history_pos += 1
1385                         self.setHistoryPath()
1386
1387         def setHistoryPath(self):
1388                 path = self.history[self.history_pos][:]
1389                 ref = path.pop()
1390                 del self.servicePath[:]
1391                 self.servicePath += path
1392                 self.saveRoot()
1393                 root = path[-1]
1394                 cur_root = self.getRoot()
1395                 if cur_root and cur_root != root:
1396                         self.setRoot(root)
1397                 self.session.nav.playService(ref)
1398                 self.setCurrentSelection(ref)
1399                 self.saveChannel(ref)
1400
1401         def saveRoot(self):
1402                 path = ''
1403                 for i in self.servicePath:
1404                         path += i.toString()
1405                         path += ';'
1406                 if path and path != self.lastroot.value:
1407                         self.lastroot.value = path
1408                         self.lastroot.save()
1409
1410         def restoreRoot(self):
1411                 tmp = [x for x in self.lastroot.value.split(';') if x != '']
1412                 current = [x.toString() for x in self.servicePath]
1413                 if tmp != current or self.rootChanged:
1414                         self.clearPath()
1415                         cnt = 0
1416                         for i in tmp:
1417                                 self.servicePath.append(eServiceReference(i))
1418                                 cnt += 1
1419                         if cnt:
1420                                 path = self.servicePath.pop()
1421                                 self.enterPath(path)
1422                         else:
1423                                 self.showFavourites()
1424                                 self.saveRoot()
1425                         self.rootChanged = False
1426
1427         def preEnterPath(self, refstr):
1428                 if self.servicePath and self.servicePath[0] != eServiceReference(refstr):
1429                         pathstr = self.lastroot.value
1430                         if pathstr is not None and pathstr.find(refstr) == 0:
1431                                 self.restoreRoot()
1432                                 lastservice=eServiceReference(self.lastservice.value)
1433                                 if lastservice.valid():
1434                                         self.setCurrentSelection(lastservice)
1435                                 return True
1436                 return False
1437
1438         def saveChannel(self, ref):
1439                 if ref is not None:
1440                         refstr = ref.toString()
1441                 else:
1442                         refstr = ""
1443                 if refstr != self.lastservice.value:
1444                         self.lastservice.value = refstr
1445                         self.lastservice.save()
1446
1447         def setCurrentServicePath(self, path):
1448                 if self.history:
1449                         self.history[self.history_pos] = path
1450                 else:
1451                         self.history.append(path)
1452                 self.setHistoryPath()
1453
1454         def getCurrentServicePath(self):
1455                 if self.history:
1456                         return self.history[self.history_pos]
1457                 return None
1458
1459         def recallPrevService(self):
1460                 hlen = len(self.history)
1461                 if hlen > 1:
1462                         if self.history_pos == hlen-1:
1463                                 tmp = self.history[self.history_pos]
1464                                 self.history[self.history_pos] = self.history[self.history_pos-1]
1465                                 self.history[self.history_pos-1] = tmp
1466                         else:
1467                                 tmp = self.history[self.history_pos+1]
1468                                 self.history[self.history_pos+1] = self.history[self.history_pos]
1469                                 self.history[self.history_pos] = tmp
1470                         self.setHistoryPath()
1471
1472         def cancel(self):
1473                 if self.revertMode is None:
1474                         self.restoreRoot()
1475                         lastservice=eServiceReference(self.lastservice.value)
1476                         if lastservice.valid() and self.getCurrentSelection() != lastservice:
1477                                 self.setCurrentSelection(lastservice)
1478                 elif self.revertMode == MODE_TV:
1479                         self.setModeTv()
1480                 elif self.revertMode == MODE_RADIO:
1481                         self.setModeRadio()
1482                 self.revertMode = None
1483                 self.close(None)
1484
1485 class RadioInfoBar(Screen):
1486         def __init__(self, session):
1487                 Screen.__init__(self, session)
1488                 self["RdsDecoder"] = RdsDecoder(self.session.nav)
1489
1490 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, InfoBarBase):
1491         ALLOW_SUSPEND = True
1492
1493         def __init__(self, session, infobar):
1494                 ChannelSelectionBase.__init__(self, session)
1495                 ChannelSelectionEdit.__init__(self)
1496                 ChannelSelectionEPG.__init__(self)
1497                 InfoBarBase.__init__(self)
1498                 self.infobar = infobar
1499                 self.onLayoutFinish.append(self.onCreate)
1500
1501                 self.info = session.instantiateDialog(RadioInfoBar) # our simple infobar
1502
1503                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1504                         {
1505                                 "keyTV": self.cancel,
1506                                 "keyRadio": self.cancel,
1507                                 "cancel": self.cancel,
1508                                 "ok": self.channelSelected,
1509                         })
1510
1511                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1512                         {
1513                                 iPlayableService.evStart: self.__evServiceStart,
1514                                 iPlayableService.evEnd: self.__evServiceEnd
1515                         })
1516
1517 ########## RDS Radiotext / Rass Support BEGIN
1518                 self.infobar = infobar # reference to real infobar (the one and only)
1519                 self["RdsDecoder"] = self.info["RdsDecoder"]
1520                 self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions",
1521                 {
1522                         "startRassInteractive": (self.startRassInteractive, _("View Rass interactive..."))
1523                 },-1)
1524                 self["RdsActions"].setEnabled(False)
1525                 infobar.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
1526                 self.onClose.append(self.__onClose)
1527
1528         def __onClose(self):
1529                 self.infobar.rds_display.onRassInteractivePossibilityChanged.remove(self.RassInteractivePossibilityChanged)
1530                 lastservice=eServiceReference(config.tv.lastservice.value)
1531                 self.session.nav.playService(lastservice)
1532
1533         def startRassInteractive(self):
1534                 self.info.hide();
1535                 self.infobar.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
1536
1537         def RassInteractiveClosed(self):
1538                 self.info.show()
1539                 self.infobar.rass_interactive = None
1540                 self.infobar.RassSlidePicChanged()
1541
1542         def RassInteractivePossibilityChanged(self, state):
1543                 self["RdsActions"].setEnabled(state)
1544 ########## RDS Radiotext / Rass Support END
1545
1546         def cancel(self):
1547                 self.info.hide()
1548                 #set previous tv service
1549                 self.close(None)
1550
1551         def __evServiceStart(self):
1552                 service = self.session.nav.getCurrentService()
1553                 if service:
1554                         info = service.info()
1555                         if info:
1556                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1557                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1558
1559         def __evServiceEnd(self):
1560                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1561
1562         def saveRoot(self):
1563                 path = ''
1564                 for i in self.servicePathRadio:
1565                         path += i.toString()
1566                         path += ';'
1567                 if path and path != config.radio.lastroot.value:
1568                         config.radio.lastroot.value = path
1569                         config.radio.lastroot.save()
1570
1571         def restoreRoot(self):
1572                 tmp = [x for x in config.radio.lastroot.value.split(';') if x != '']
1573                 current = [x.toString() for x in self.servicePathRadio]
1574                 if tmp != current or self.rootChanged:
1575                         self.clearPath()
1576                         cnt = 0
1577                         for i in tmp:
1578                                 self.servicePathRadio.append(eServiceReference(i))
1579                                 cnt += 1
1580                         if cnt:
1581                                 path = self.servicePathRadio.pop()
1582                                 self.enterPath(path)
1583                         else:
1584                                 self.showFavourites()
1585                                 self.saveRoot()
1586                         self.rootChanged = False
1587
1588         def preEnterPath(self, refstr):
1589                 if self.servicePathRadio and self.servicePathRadio[0] != eServiceReference(refstr):
1590                         pathstr = config.radio.lastroot.value
1591                         if pathstr is not None and pathstr.find(refstr) == 0:
1592                                 self.restoreRoot()
1593                                 lastservice=eServiceReference(config.radio.lastservice.value)
1594                                 if lastservice.valid():
1595                                         self.setCurrentSelection(lastservice)
1596                                 return True
1597                 return False
1598
1599         def onCreate(self):
1600                 self.setRadioMode()
1601                 self.restoreRoot()
1602                 lastservice=eServiceReference(config.radio.lastservice.value)
1603                 if lastservice.valid():
1604                         self.servicelist.setCurrent(lastservice)
1605                         self.session.nav.playService(lastservice)
1606                 else:
1607                         self.session.nav.stopService()
1608                 self.info.show()
1609
1610         def channelSelected(self): # just return selected service
1611                 ref = self.getCurrentSelection()
1612                 if self.movemode:
1613                         self.toggleMoveMarked()
1614                 elif (ref.flags & 7) == 7:
1615                         self.enterPath(ref)
1616                 elif self.bouquet_mark_edit != OFF:
1617                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1618                                 self.doMark()
1619                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1620                         cur_root = self.getRoot()
1621                         if not cur_root or not (cur_root.flags & eServiceReference.isGroup):
1622                                 playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1623                                 if playingref is None or playingref != ref:
1624                                         self.session.nav.playService(ref)
1625                                         config.radio.lastservice.value = ref.toString()
1626                                         config.radio.lastservice.save()
1627                                 self.saveRoot()
1628
1629 class SimpleChannelSelection(ChannelSelectionBase):
1630         def __init__(self, session, title):
1631                 ChannelSelectionBase.__init__(self, session)
1632                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1633                         {
1634                                 "cancel": self.close,
1635                                 "ok": self.channelSelected,
1636                                 "keyRadio": self.setModeRadio,
1637                                 "keyTV": self.setModeTv,
1638                         })
1639                 self.title = title
1640                 self.onLayoutFinish.append(self.layoutFinished)
1641
1642         def layoutFinished(self):
1643                 self.setModeTv()
1644
1645         def channelSelected(self): # just return selected service
1646                 ref = self.getCurrentSelection()
1647                 if (ref.flags & 7) == 7:
1648                         self.enterPath(ref)
1649                 elif not (ref.flags & eServiceReference.isMarker):
1650                         ref = self.getCurrentSelection()
1651                         self.close(ref)
1652
1653         def setModeTv(self):
1654                 self.setTvMode()
1655                 self.showFavourites()
1656
1657         def setModeRadio(self):
1658                 self.setRadioMode()
1659                 self.showFavourites()