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