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