fix typo (apend -> append)
[enigma2.git] / 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, eTimer, eDVBDB, iPlayableService, iServiceInformation
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):
65         if current and current.valid():
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))
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())))
99                                                 else:
100                                                         append_when_current_valid(current, menu, (_("remove from parental protection"), boundFunction(self.removeParentalProtection, csel.getCurrentSelection())))
101                                         if haveBouquets:
102                                                 append_when_current_valid(current, menu, (_("add service to bouquet"), self.addServiceToBouquetSelected))
103                                         else:
104                                                 append_when_current_valid(current, menu, (_("add service to favourites"), self.addServiceToBouquetSelected))
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))
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))
111                                 if inBouquet:
112                                         append_when_current_valid(current, menu, (_("remove entry"), self.removeCurrentService))
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))
115                         else:
116                                         menu.append((_("add bouquet"), self.showBouquetInputBox))
117                                         append_when_current_valid(current, menu, (_("remove entry"), self.removeBouquet))
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))
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))
127                                                 else:
128                                                         append_when_current_valid(current, menu, (_("enable favourite edit"), self.bouquetMarkStart))
129                                                 if current_sel_flags & eServiceReference.isGroup:
130                                                         append_when_current_valid(current, menu, (_("edit alternatives"), self.editAlternativeServices))
131                                                         append_when_current_valid(current, menu, (_("show alternatives"), self.showAlternativeServices))
132                                                         append_when_current_valid(current, menu, (_("remove all alternatives"), self.removeAlternativeServices))
133                                                 elif not current_sel_flags & eServiceReference.isMarker:
134                                                         append_when_current_valid(current, menu, (_("add alternatives"), self.addAlternativeServices))
135                                 else:
136                                         append_when_current_valid(current, menu, (_("disable move mode"), self.toggleMoveMode))
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))
141                                                 append_when_current_valid(current, menu, (_("abort bouquet edit"), self.bouquetMarkAbort))
142                                         else:
143                                                 append_when_current_valid(current, menu, (_("end favourites edit"), self.bouquetMarkEnd))
144                                                 append_when_current_valid(current, menu, (_("abort favourites edit"), self.bouquetMarkAbort))
145                                 else:
146                                                 append_when_current_valid(current, menu, (_("end alternatives edit"), self.bouquetMarkEnd))
147                                                 append_when_current_valid(current, menu, (_("abort alternatives edit"), self.bouquetMarkAbort))
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, 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, 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"],
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                                 "1": self.keyNumberGlobal,
662                                 "2": self.keyNumberGlobal,
663                                 "3": self.keyNumberGlobal,
664                                 "4": self.keyNumberGlobal,
665                                 "5": self.keyNumberGlobal,
666                                 "6": self.keyNumberGlobal,
667                                 "7": self.keyNumberGlobal,
668                                 "8": self.keyNumberGlobal,
669                                 "9": self.keyNumberGlobal,
670                                 "0": self.keyNumber0
671                         })
672                 self.recallBouquetMode()
673
674         def getBouquetNumOffset(self, bouquet):
675                 if not config.usage.multibouquet.value:
676                         return 0
677                 str = bouquet.toString()
678                 offsetCount = 0
679                 if not self.bouquetNumOffsetCache.has_key(str):
680                         serviceHandler = eServiceCenter.getInstance()
681                         bouquetlist = serviceHandler.list(self.bouquet_root)
682                         if not bouquetlist is None:
683                                 while True:
684                                         bouquetIterator = bouquetlist.getNext()
685                                         if not bouquetIterator.valid(): #end of list
686                                                 break
687                                         self.bouquetNumOffsetCache[bouquetIterator.toString()]=offsetCount
688                                         if not (bouquetIterator.flags & eServiceReference.isDirectory):
689                                                 continue
690                                         servicelist = serviceHandler.list(bouquetIterator)
691                                         if not servicelist is None:
692                                                 while True:
693                                                         serviceIterator = servicelist.getNext()
694                                                         if not serviceIterator.valid(): #check if end of list
695                                                                 break
696                                                         playable = not (serviceIterator.flags & (eServiceReference.isDirectory|eServiceReference.isMarker))
697                                                         if playable:
698                                                                 offsetCount += 1
699                 return self.bouquetNumOffsetCache.get(str, offsetCount)
700
701         def recallBouquetMode(self):
702                 if self.mode == MODE_TV:
703                         self.service_types = service_types_tv
704                         if config.usage.multibouquet.value:
705                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.tv" ORDER BY bouquet'
706                         else:
707                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)
708                 else:
709                         self.service_types = service_types_radio
710                         if config.usage.multibouquet.value:
711                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.radio" ORDER BY bouquet'
712                         else:
713                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(self.service_types)
714                 self.bouquet_root = eServiceReference(self.bouquet_rootstr)
715
716         def setTvMode(self):
717                 self.mode = MODE_TV
718                 self.servicePath = self.servicePathTV
719                 self.recallBouquetMode()
720                 title = self.instance.getTitle()
721                 pos = title.find(" (")
722                 if pos != -1:
723                         title = title[:pos]
724                 title += " (TV)"
725                 self.setTitle(title)
726
727         def setRadioMode(self):
728                 self.mode = MODE_RADIO
729                 self.servicePath = self.servicePathRadio
730                 self.recallBouquetMode()
731                 title = self.instance.getTitle()
732                 pos = title.find(" (")
733                 if pos != -1:
734                         title = title[:pos]
735                 title += " (Radio)"
736                 self.setTitle(title)
737
738         def setRoot(self, root, justSet=False):
739                 path = root.getPath()
740                 inBouquetRootList = path.find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
741                 pos = path.find('FROM BOUQUET')
742                 isBouquet = (pos != -1) and (root.flags & eServiceReference.isDirectory)
743                 if not inBouquetRootList and isBouquet:
744                         self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
745                         self.servicelist.setNumberOffset(self.getBouquetNumOffset(root))
746                 else:
747                         self.servicelist.setMode(ServiceList.MODE_NORMAL)
748                 self.servicelist.setRoot(root, justSet)
749                 self.buildTitleString()
750
751         def removeModeStr(self, str):
752                 if self.mode == MODE_TV:
753                         pos = str.find(' (TV)')
754                 else:
755                         pos = str.find(' (Radio)')
756                 if pos != -1:
757                         return str[:pos]
758                 return str
759
760         def getServiceName(self, ref):
761                 str = self.removeModeStr(ServiceReference(ref).getServiceName())
762                 if not len(str):
763                         pathstr = ref.getPath()
764                         if pathstr.find('FROM PROVIDERS') != -1:
765                                 return _("Provider")
766                         if pathstr.find('FROM SATELLITES') != -1:
767                                 return _("Satellites")
768                         if pathstr.find(') ORDER BY name') != -1:
769                                 return _("All")
770                 return str
771
772         def buildTitleString(self):
773                 titleStr = self.instance.getTitle()
774                 pos = titleStr.find(']')
775                 if pos == -1:
776                         pos = titleStr.find(')')
777                 if pos != -1:
778                         titleStr = titleStr[:pos+1]
779                         Len = len(self.servicePath)
780                         if Len > 0:
781                                 base_ref = self.servicePath[0]
782                                 if Len > 1:
783                                         end_ref = self.servicePath[Len-1]
784                                 else:
785                                         end_ref = None
786                                 nameStr = self.getServiceName(base_ref)
787                                 titleStr += ' ' + nameStr
788                                 if end_ref is not None:
789                                         if Len > 2:
790                                                 titleStr += '/../'
791                                         else:
792                                                 titleStr += '/'
793                                         nameStr = self.getServiceName(end_ref)
794                                         titleStr += nameStr
795                                 self.setTitle(titleStr)
796
797         def moveUp(self):
798                 self.servicelist.moveUp()
799
800         def moveDown(self):
801                 self.servicelist.moveDown()
802
803         def clearPath(self):
804                 del self.servicePath[:]
805
806         def enterPath(self, ref, justSet=False):
807                 self.servicePath.append(ref)
808                 self.setRoot(ref, justSet)
809
810         def pathUp(self, justSet=False):
811                 prev = self.servicePath.pop()
812                 length = len(self.servicePath)
813                 if length:
814                         current = self.servicePath[length-1]
815                         self.setRoot(current, justSet)
816                         if not justSet:
817                                 self.setCurrentSelection(prev)
818                 return prev
819
820         def isBasePathEqual(self, ref):
821                 if len(self.servicePath) > 1 and self.servicePath[0] == ref:
822                         return True
823                 return False
824
825         def isPrevPathEqual(self, ref):
826                 length = len(self.servicePath)
827                 if length > 1 and self.servicePath[length-2] == ref:
828                         return True
829                 return False
830
831         def preEnterPath(self, refstr):
832                 return False
833
834         def showAllServices(self):
835                 if not self.pathChangeDisabled:
836                         refstr = '%s ORDER BY name'%(self.service_types)
837                         if not self.preEnterPath(refstr):
838                                 ref = eServiceReference(refstr)
839                                 currentRoot = self.getRoot()
840                                 if currentRoot is None or currentRoot != ref:
841                                         self.clearPath()
842                                         self.enterPath(ref)
843
844         def showSatellites(self):
845                 if not self.pathChangeDisabled:
846                         refstr = '%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)
847                         if not self.preEnterPath(refstr):
848                                 ref = eServiceReference(refstr)
849                                 justSet=False
850                                 prev = None
851
852                                 if self.isBasePathEqual(ref):
853                                         if self.isPrevPathEqual(ref):
854                                                 justSet=True
855                                         prev = self.pathUp(justSet)
856                                 else:
857                                         currentRoot = self.getRoot()
858                                         if currentRoot is None or currentRoot != ref:
859                                                 justSet=True
860                                                 self.clearPath()
861                                                 self.enterPath(ref, True)
862                                 if justSet:
863                                         serviceHandler = eServiceCenter.getInstance()
864                                         servicelist = serviceHandler.list(ref)
865                                         if not servicelist is None:
866                                                 while True:
867                                                         service = servicelist.getNext()
868                                                         if not service.valid(): #check if end of list
869                                                                 break
870                                                         orbpos = service.getUnsignedData(4) >> 16
871                                                         if service.getPath().find("FROM PROVIDER") != -1:
872                                                                 service_type = _("Providers")
873                                                         elif service.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
874                                                                 service_type = _("New")
875                                                         else:
876                                                                 service_type = _("Services")
877                                                         try:
878                                                                 # why we need this cast?
879                                                                 service_name = str(nimmanager.getSatDescription(orbpos))
880                                                         except:
881                                                                 if orbpos == 0xFFFF: #Cable
882                                                                         service_name = _("Cable")
883                                                                 elif orbpos == 0xEEEE: #Terrestrial
884                                                                         service_name = _("Terrestrial")
885                                                                 else:
886                                                                         if orbpos > 1800: # west
887                                                                                 orbpos = 3600 - orbpos
888                                                                                 h = _("W")
889                                                                         else:
890                                                                                 h = _("E")
891                                                                         service_name = ("%d.%d" + h) % (orbpos / 10, orbpos % 10)
892                                                         service.setName("%s - %s" % (service_name, service_type))
893                                                         self.servicelist.addService(service)
894                                                 cur_ref = self.session.nav.getCurrentlyPlayingServiceReference()
895                                                 if cur_ref:
896                                                         pos = self.service_types.rfind(':')
897                                                         refstr = '%s (channelID == %08x%04x%04x) && %s ORDER BY name' %(self.service_types[:pos+1],
898                                                                 cur_ref.getUnsignedData(4), # NAMESPACE
899                                                                 cur_ref.getUnsignedData(2), # TSID
900                                                                 cur_ref.getUnsignedData(3), # ONID
901                                                                 self.service_types[pos+1:])
902                                                         ref = eServiceReference(refstr)
903                                                         ref.setName(_("Current Transponder"))
904                                                         self.servicelist.addService(ref)
905                                                 self.servicelist.finishFill()
906                                                 if prev is not None:
907                                                         self.setCurrentSelection(prev)
908
909         def showProviders(self):
910                 if not self.pathChangeDisabled:
911                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
912                         if not self.preEnterPath(refstr):
913                                 ref = eServiceReference(refstr)
914                                 if self.isBasePathEqual(ref):
915                                         self.pathUp()
916                                 else:
917                                         currentRoot = self.getRoot()
918                                         if currentRoot is None or currentRoot != ref:
919                                                 self.clearPath()
920                                                 self.enterPath(ref)
921
922         def changeBouquet(self, direction):
923                 if not self.pathChangeDisabled:
924                         if len(self.servicePath) > 1:
925                                 #when enter satellite root list we must do some magic stuff..
926                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
927                                 if self.isBasePathEqual(ref):
928                                         self.showSatellites()
929                                 else:
930                                         self.pathUp()
931                                 if direction < 0:
932                                         self.moveUp()
933                                 else:
934                                         self.moveDown()
935                                 ref = self.getCurrentSelection()
936                                 self.enterPath(ref)
937
938         def inBouquet(self):
939                 if len(self.servicePath) > 0 and self.servicePath[0] == self.bouquet_root:
940                         return True
941                 return False
942
943         def atBegin(self):
944                 return self.servicelist.atBegin()
945
946         def atEnd(self):
947                 return self.servicelist.atEnd()
948
949         def nextBouquet(self):
950                 self.changeBouquet(+1)
951
952         def prevBouquet(self):
953                 self.changeBouquet(-1)
954
955         def showFavourites(self):
956                 if not self.pathChangeDisabled:
957                         if not self.preEnterPath(self.bouquet_rootstr):
958                                 if self.isBasePathEqual(self.bouquet_root):
959                                         self.pathUp()
960                                 else:
961                                         currentRoot = self.getRoot()
962                                         if currentRoot is None or currentRoot != self.bouquet_root:
963                                                 self.clearPath()
964                                                 self.enterPath(self.bouquet_root)
965
966         def keyNumberGlobal(self, number):
967                 unichar = self.numericalTextInput.getKey(number)
968                 charstr = unichar.encode("utf-8")
969                 if len(charstr) == 1:
970                         self.servicelist.moveToChar(charstr[0])
971
972         def getRoot(self):
973                 return self.servicelist.getRoot()
974
975         def getCurrentSelection(self):
976                 return self.servicelist.getCurrent()
977
978         def setCurrentSelection(self, service):
979                 servicepath = service.getPath()
980                 pos = servicepath.find(" FROM BOUQUET")
981                 if pos != -1:
982                         if self.mode == MODE_TV:
983                                 servicepath = '(type == 1)' + servicepath[pos:]
984                         else:
985                                 servicepath = '(type == 2)' + servicepath[pos:]
986                         service.setPath(servicepath)
987                 self.servicelist.setCurrent(service)
988
989         def getBouquetList(self):
990                 bouquets = [ ]
991                 serviceHandler = eServiceCenter.getInstance()
992                 if config.usage.multibouquet.value:
993                         list = serviceHandler.list(self.bouquet_root)
994                         if list:
995                                 while True:
996                                         s = list.getNext()
997                                         if not s.valid():
998                                                 break
999                                         if s.flags & eServiceReference.isDirectory:
1000                                                 info = serviceHandler.info(s)
1001                                                 if info:
1002                                                         bouquets.append((info.getName(s), s))
1003                                 return bouquets
1004                 else:
1005                         info = serviceHandler.info(self.bouquet_root)
1006                         if info:
1007                                 bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
1008                         return bouquets
1009                 return None
1010
1011         def keyNumber0(self, num):
1012                 if len(self.servicePath) > 1:
1013                         self.keyGoUp()
1014                 else:
1015                         self.keyNumberGlobal(num)
1016
1017         def keyGoUp(self):
1018                 if len(self.servicePath) > 1:
1019                         if self.isBasePathEqual(self.bouquet_root):
1020                                 self.showFavourites()
1021                         else:
1022                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
1023                                 if self.isBasePathEqual(ref):
1024                                         self.showSatellites()
1025                                 else:
1026                                         ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
1027                                         if self.isBasePathEqual(ref):
1028                                                 self.showProviders()
1029                                         else:
1030                                                 self.showAllServices()
1031
1032         def nextMarker(self):
1033                 self.servicelist.moveToNextMarker()
1034
1035         def prevMarker(self):
1036                 self.servicelist.moveToPrevMarker()
1037
1038 HISTORYSIZE = 20
1039
1040 #config for lastservice
1041 config.tv = ConfigSubsection()
1042 config.tv.lastservice = ConfigText()
1043 config.tv.lastroot = ConfigText()
1044 config.radio = ConfigSubsection()
1045 config.radio.lastservice = ConfigText()
1046 config.radio.lastroot = ConfigText()
1047 config.servicelist = ConfigSubsection()
1048 config.servicelist.lastmode = ConfigText(default = "tv")
1049
1050 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, SelectionEventInfo):
1051         def __init__(self, session):
1052                 ChannelSelectionBase.__init__(self,session)
1053                 ChannelSelectionEdit.__init__(self)
1054                 ChannelSelectionEPG.__init__(self)
1055                 SelectionEventInfo.__init__(self)
1056
1057                 self["CurrentTime"] = ObsoleteSource(new_source = "global.CurrentTime", removal_date = "2008-01")
1058
1059                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1060                         {
1061                                 "cancel": self.cancel,
1062                                 "ok": self.channelSelected,
1063                                 "keyRadio": self.setModeRadio,
1064                                 "keyTV": self.setModeTv,
1065                         })
1066
1067                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1068                         {
1069                                 iPlayableService.evStart: self.__evServiceStart,
1070                                 iPlayableService.evEnd: self.__evServiceEnd
1071                         })
1072
1073                 self.lastChannelRootTimer = eTimer()
1074                 self.lastChannelRootTimer.timeout.get().append(self.__onCreate)
1075                 self.lastChannelRootTimer.start(100,True)
1076
1077                 self.history_tv = [ ]
1078                 self.history_radio = [ ]
1079                 self.history = self.history_tv
1080                 self.history_pos = 0
1081
1082                 self.lastservice = config.tv.lastservice
1083                 self.lastroot = config.tv.lastroot
1084                 self.revertMode = None
1085                 config.usage.multibouquet.addNotifier(self.multibouquet_config_changed)
1086                 self.new_service_played = False
1087
1088         def multibouquet_config_changed(self, val):
1089                 self.recallBouquetMode()
1090
1091         def __evServiceStart(self):
1092                 service = self.session.nav.getCurrentService()
1093                 if service:
1094                         info = service.info()
1095                         if info:
1096                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1097                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1098
1099         def __evServiceEnd(self):
1100                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1101
1102         def setMode(self):
1103                 self.restoreRoot()
1104                 lastservice=eServiceReference(self.lastservice.value)
1105                 if lastservice.valid():
1106                         self.setCurrentSelection(lastservice)
1107
1108         def setModeTv(self):
1109                 if self.revertMode is None and config.servicelist.lastmode.value == "radio":
1110                         self.revertMode = MODE_RADIO
1111                 self.history = self.history_tv
1112                 self.lastservice = config.tv.lastservice
1113                 self.lastroot = config.tv.lastroot
1114                 config.servicelist.lastmode.value = "tv"
1115                 self.setTvMode()
1116                 self.setMode()
1117
1118         def setModeRadio(self):
1119                 if self.revertMode is None and config.servicelist.lastmode.value == "tv":
1120                         self.revertMode = MODE_TV
1121                 if config.usage.e1like_radio_mode.value:
1122                         self.history = self.history_radio
1123                         self.lastservice = config.radio.lastservice
1124                         self.lastroot = config.radio.lastroot
1125                         config.servicelist.lastmode.value = "radio"
1126                         self.setRadioMode()
1127                         self.setMode()
1128
1129         def __onCreate(self):
1130                 if config.usage.e1like_radio_mode.value:
1131                         if config.servicelist.lastmode.value == "tv":
1132                                 self.setModeTv()
1133                         else:
1134                                 self.setModeRadio()
1135                 else:
1136                         self.setModeTv()
1137                 lastservice=eServiceReference(self.lastservice.value)
1138                 if lastservice.valid():
1139                         self.zap()
1140
1141         def channelSelected(self):
1142                 ref = self.getCurrentSelection()
1143                 if self.movemode:
1144                         self.toggleMoveMarked()
1145                 elif (ref.flags & 7) == 7:
1146                         self.enterPath(ref)
1147                 elif self.bouquet_mark_edit != OFF:
1148                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1149                                 self.doMark()
1150                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1151                         root = self.getRoot()
1152                         if not root or not (root.flags & eServiceReference.isGroup):
1153                                 self.zap()
1154                                 self.close(ref)
1155
1156         #called from infoBar and channelSelected
1157         def zap(self):
1158                 self.revertMode=None
1159                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1160                 nref = self.getCurrentSelection()
1161                 if ref is None or ref != nref:
1162                         self.new_service_played = True
1163                         self.session.nav.playService(nref)
1164                         self.saveRoot()
1165                         self.saveChannel(nref)
1166                         config.servicelist.lastmode.save()
1167                         self.addToHistory(nref)
1168
1169         def newServicePlayed(self):
1170                 ret = self.new_service_played
1171                 self.new_service_played = False
1172                 return ret
1173
1174         def addToHistory(self, ref):
1175                 if self.servicePath is not None:
1176                         tmp=self.servicePath[:]
1177                         tmp.append(ref)
1178                         try:
1179                                 del self.history[self.history_pos+1:]
1180                         except:
1181                                 pass
1182                         self.history.append(tmp)
1183                         hlen = len(self.history)
1184                         if hlen > HISTORYSIZE:
1185                                 del self.history[0]
1186                                 hlen -= 1
1187                         self.history_pos = hlen-1
1188
1189         def historyBack(self):
1190                 hlen = len(self.history)
1191                 if hlen > 1 and self.history_pos > 0:
1192                         self.history_pos -= 1
1193                         self.setHistoryPath()
1194
1195         def historyNext(self):
1196                 hlen = len(self.history)
1197                 if hlen > 1 and self.history_pos < (hlen-1):
1198                         self.history_pos += 1
1199                         self.setHistoryPath()
1200
1201         def setHistoryPath(self):
1202                 path = self.history[self.history_pos][:]
1203                 ref = path.pop()
1204                 del self.servicePath[:]
1205                 self.servicePath += path
1206                 self.saveRoot()
1207                 plen = len(path)
1208                 root = path[plen-1]
1209                 cur_root = self.getRoot()
1210                 if cur_root and cur_root != root:
1211                         self.setRoot(root)
1212                 self.session.nav.playService(ref)
1213                 self.setCurrentSelection(ref)
1214                 self.saveChannel(ref)
1215
1216         def saveRoot(self):
1217                 path = ''
1218                 for i in self.servicePath:
1219                         path += i.toString()
1220                         path += ';'
1221                 if len(path) and path != self.lastroot.value:
1222                         self.lastroot.value = path
1223                         self.lastroot.save()
1224
1225         def restoreRoot(self):
1226                 self.clearPath()
1227                 re = compile('.+?;')
1228                 tmp = re.findall(self.lastroot.value)
1229                 cnt = 0
1230                 for i in tmp:
1231                         self.servicePath.append(eServiceReference(i[:len(i)-1]))
1232                         cnt += 1
1233                 if cnt:
1234                         path = self.servicePath.pop()
1235                         self.enterPath(path)
1236                 else:
1237                         self.showFavourites()
1238                         self.saveRoot()
1239
1240         def preEnterPath(self, refstr):
1241                 if len(self.servicePath) and self.servicePath[0] != eServiceReference(refstr):
1242                         pathstr = self.lastroot.value
1243                         if pathstr is not None and pathstr.find(refstr) == 0:
1244                                 self.restoreRoot()
1245                                 lastservice=eServiceReference(self.lastservice.value)
1246                                 if lastservice.valid():
1247                                         self.setCurrentSelection(lastservice)
1248                                 return True
1249                 return False
1250
1251         def saveChannel(self, ref):
1252                 if ref is not None:
1253                         refstr = ref.toString()
1254                 else:
1255                         refstr = ""
1256                 if refstr != self.lastservice.value:
1257                         self.lastservice.value = refstr
1258                         self.lastservice.save()
1259
1260         def setCurrentServicePath(self, path):
1261                 hlen = len(self.history)
1262                 if hlen > 0:
1263                         self.history[self.history_pos] = path
1264                 else:
1265                         self.history.append(path)
1266                 self.setHistoryPath()
1267
1268         def getCurrentServicePath(self):
1269                 hlen = len(self.history)
1270                 if hlen > 0:
1271                         return self.history[self.history_pos]
1272                 return None
1273
1274         def recallPrevService(self):
1275                 hlen = len(self.history)
1276                 if hlen > 1:
1277                         if self.history_pos == hlen-1:
1278                                 tmp = self.history[self.history_pos]
1279                                 self.history[self.history_pos] = self.history[self.history_pos-1]
1280                                 self.history[self.history_pos-1] = tmp
1281                         else:
1282                                 tmp = self.history[self.history_pos+1]
1283                                 self.history[self.history_pos+1] = self.history[self.history_pos]
1284                                 self.history[self.history_pos] = tmp
1285                         self.setHistoryPath()
1286
1287         def cancel(self):
1288                 if self.revertMode is None:
1289                         self.restoreRoot()
1290                         lastservice=eServiceReference(self.lastservice.value)
1291                         if lastservice.valid() and self.getCurrentSelection() != lastservice:
1292                                 self.setCurrentSelection(lastservice)
1293                 elif self.revertMode == MODE_TV:
1294                         self.setModeTv()
1295                 elif self.revertMode == MODE_RADIO:
1296                         self.setModeRadio()
1297                 self.revertMode = None
1298                 self.close(None)
1299
1300 from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName
1301
1302 class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName):
1303         def __init__(self, session):
1304                 Screen.__init__(self, session)
1305                 InfoBarEvent.__init__(self)
1306                 InfoBarServiceName.__init__(self)
1307                 self["CurrentTime"] = ObsoleteSource(new_source = "global.CurrentTime", removal_date = "2008-01")
1308                 self["RdsDecoder"] = RdsDecoder(self.session.nav)
1309                 self["BlinkingPoint"] = Pixmap()
1310                 self["BlinkingPoint"].hide()
1311
1312 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
1313         ALLOW_SUSPEND = True
1314
1315         def __init__(self, session, infobar):
1316                 ChannelSelectionBase.__init__(self, session)
1317                 ChannelSelectionEdit.__init__(self)
1318                 ChannelSelectionEPG.__init__(self)
1319                 self.infobar = infobar
1320                 self.onLayoutFinish.append(self.onCreate)
1321
1322                 self.info = session.instantiateDialog(RadioInfoBar) # our simple infobar
1323
1324                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1325                         {
1326                                 "keyTV": self.closeRadio,
1327                                 "keyRadio": self.closeRadio,
1328                                 "cancel": self.closeRadio,
1329                                 "ok": self.channelSelected,
1330                         })
1331
1332                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1333                         {
1334                                 iPlayableService.evStart: self.__evServiceStart,
1335                                 iPlayableService.evEnd: self.__evServiceEnd
1336                         })
1337
1338 ########## RDS Radiotext / Rass Support BEGIN
1339                 self.infobar = infobar # reference to real infobar (the one and only)
1340                 self["RdsDecoder"] = self.info["RdsDecoder"]
1341                 self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions",
1342                 {
1343                         "startRassInteractive": (self.startRassInteractive, _("View Rass interactive..."))
1344                 },-1)
1345                 self["RdsActions"].setEnabled(False)
1346                 infobar.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
1347
1348         def startRassInteractive(self):
1349                 self.info.hide();
1350                 self.infobar.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
1351
1352         def RassInteractiveClosed(self):
1353                 self.info.show()
1354                 self.infobar.rass_interactive = None
1355                 self.infobar.RassSlidePicChanged()
1356
1357         def RassInteractivePossibilityChanged(self, state):
1358                 self["RdsActions"].setEnabled(state)
1359 ########## RDS Radiotext / Rass Support END
1360
1361         def closeRadio(self):
1362                 self.infobar.rds_display.onRassInteractivePossibilityChanged.remove(self.RassInteractivePossibilityChanged)
1363                 self.info.hide()
1364                 #set previous tv service
1365                 lastservice=eServiceReference(config.tv.lastservice.value)
1366                 self.session.nav.playService(lastservice)
1367                 self.close(None)
1368
1369         def __evServiceStart(self):
1370                 service = self.session.nav.getCurrentService()
1371                 if service:
1372                         info = service.info()
1373                         if info:
1374                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1375                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1376
1377         def __evServiceEnd(self):
1378                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1379
1380         def saveRoot(self):
1381                 path = ''
1382                 for i in self.servicePathRadio:
1383                         path += i.toString()
1384                         path += ';'
1385                 if len(path) and path != config.radio.lastroot.value:
1386                         config.radio.lastroot.value = path
1387                         config.radio.lastroot.save()
1388
1389         def restoreRoot(self):
1390                 self.clearPath()
1391                 re = compile('.+?;')
1392                 tmp = re.findall(config.radio.lastroot.value)
1393                 cnt = 0
1394                 for i in tmp:
1395                         self.servicePathRadio.append(eServiceReference(i[:len(i)-1]))
1396                         cnt += 1
1397                 if cnt:
1398                         path = self.servicePathRadio.pop()
1399                         self.enterPath(path)
1400                 else:
1401                         self.showFavourites()
1402                         self.saveRoot()
1403
1404         def preEnterPath(self, refstr):
1405                 if len(self.servicePathRadio) and self.servicePathRadio[0] != eServiceReference(refstr):
1406                         pathstr = config.radio.lastroot.value
1407                         if pathstr is not None and pathstr.find(refstr) == 0:
1408                                 self.restoreRoot()
1409                                 lastservice=eServiceReference(config.radio.lastservice.value)
1410                                 if lastservice.valid():
1411                                         self.setCurrentSelection(lastservice)
1412                                 return True
1413                 return False
1414
1415         def onCreate(self):
1416                 self.setRadioMode()
1417                 self.restoreRoot()
1418                 lastservice=eServiceReference(config.radio.lastservice.value)
1419                 if lastservice.valid():
1420                         self.servicelist.setCurrent(lastservice)
1421                         self.session.nav.playService(lastservice)
1422                 else:
1423                         self.session.nav.stopService()
1424                 self.info.show()
1425
1426         def channelSelected(self): # just return selected service
1427                 ref = self.getCurrentSelection()
1428                 if self.movemode:
1429                         self.toggleMoveMarked()
1430                 elif (ref.flags & 7) == 7:
1431                         self.enterPath(ref)
1432                 elif self.bouquet_mark_edit != OFF:
1433                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1434                                 self.doMark()
1435                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1436                         cur_root = self.getRoot()
1437                         if not cur_root or not (cur_root.flags & eServiceReference.isGroup):
1438                                 playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1439                                 if playingref is None or playingref != ref:
1440                                         self.session.nav.playService(ref)
1441                                         config.radio.lastservice.value = ref.toString()
1442                                         config.radio.lastservice.save()
1443                                 self.saveRoot()
1444
1445 class SimpleChannelSelection(ChannelSelectionBase):
1446         def __init__(self, session, title):
1447                 ChannelSelectionBase.__init__(self, session)
1448                 self.title = title
1449                 self.onShown.append(self.__onExecCallback)
1450
1451                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1452                         {
1453                                 "cancel": self.close,
1454                                 "ok": self.channelSelected,
1455                                 "keyRadio": self.setModeRadio,
1456                                 "keyTV": self.setModeTv,
1457                         })
1458
1459         def __onExecCallback(self):
1460                 self.setTitle(self.title)
1461                 self.setModeTv()
1462
1463         def channelSelected(self): # just return selected service
1464                 ref = self.getCurrentSelection()
1465                 if (ref.flags & 7) == 7:
1466                         self.enterPath(ref)
1467                 elif not (ref.flags & eServiceReference.isMarker):
1468                         ref = self.getCurrentSelection()
1469                         self.close(ref)
1470
1471         def setModeTv(self):
1472                 self.setTvMode()
1473                 self.showFavourites()
1474
1475         def setModeRadio(self):
1476                 self.setRadioMode()
1477                 self.showFavourites()