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