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