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