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