32c3b1079c95ffd7e82f50a4ed6d6b1e07484235
[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.getData(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 > 1800: # west
705                                                                         orbpos = 3600 - orbpos
706                                                                         h = _("W")
707                                                                 else:
708                                                                         h = _("E")
709                                                                 n = ("%s (%d.%d" + h + ")") % (service_name, orbpos / 10, orbpos % 10)
710                                                                 service.setName(n)
711                                                         self.servicelist.addService(service)
712                                                         self.servicelist.finishFill()
713                                                         if prev is not None:
714                                                                 self.setCurrentSelection(prev)
715
716         def showProviders(self):
717                 if not self.pathChangedDisabled:
718                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
719                         if not self.preEnterPath(refstr):
720                                 ref = eServiceReference(refstr)
721                                 if self.isBasePathEqual(ref):
722                                         self.pathUp()
723                                 else:
724                                         currentRoot = self.getRoot()
725                                         if currentRoot is None or currentRoot != ref:
726                                                 self.clearPath()
727                                                 self.enterPath(ref)
728
729         def changeBouquet(self, direction):
730                 if not self.pathChangedDisabled:
731                         if self.isBasePathEqual(self.bouquet_root):
732                                 self.pathUp()
733                                 if direction < 0:
734                                         self.moveUp()
735                                 else:
736                                         self.moveDown()
737                                 ref = self.getCurrentSelection()
738                                 self.enterPath(ref)
739
740         def inBouquet(self):
741                 return self.isBasePathEqual(self.bouquet_root)
742
743         def atBegin(self):
744                 return self.servicelist.atBegin()
745
746         def atEnd(self):
747                 return self.servicelist.atEnd()
748
749         def nextBouquet(self):
750                 self.changeBouquet(+1)
751
752         def prevBouquet(self):
753                 self.changeBouquet(-1)
754
755         def showFavourites(self):
756                 if not self.pathChangedDisabled:
757                         if not self.preEnterPath(self.bouquet_rootstr):
758                                 if self.isBasePathEqual(self.bouquet_root):
759                                         self.pathUp()
760                                 else:
761                                         currentRoot = self.getRoot()
762                                         if currentRoot is None or currentRoot != self.bouquet_root:
763                                                 self.clearPath()
764                                                 self.enterPath(self.bouquet_root)
765
766         def keyNumberGlobal(self, number):
767                 char = self.numericalTextInput.getKey(number)
768                 self.servicelist.moveToChar(char)
769
770         def getRoot(self):
771                 return self.servicelist.getRoot()
772
773         def getCurrentSelection(self):
774                 return self.servicelist.getCurrent()
775
776         def setCurrentSelection(self, service):
777                 servicepath = service.getPath()
778                 pos = servicepath.find(" FROM BOUQUET")
779                 if pos != -1:
780                         if self.mode == MODE_TV:
781                                 servicepath = '(type == 1)' + servicepath[pos:]
782                         else:
783                                 servicepath = '(type == 2)' + servicepath[pos:]
784                         service.setPath(servicepath)
785                 self.servicelist.setCurrent(service)
786
787         def getBouquetList(self):
788                 serviceCount=0
789                 bouquets = [ ]
790                 serviceHandler = eServiceCenter.getInstance()
791                 list = serviceHandler.list(self.bouquet_root)
792                 if not list is None:
793                         while True:
794                                 s = list.getNext()
795                                 if not s.valid():
796                                         break
797                                 if ((s.flags & eServiceReference.flagDirectory) == eServiceReference.flagDirectory):
798                                         info = serviceHandler.info(s)
799                                         if not info is None:
800                                                 bouquets.append((info.getName(s), s))
801                                 else:
802                                         serviceCount += 1
803                         if len(bouquets) == 0 and serviceCount > 0:
804                                 info = serviceHandler.info(self.bouquet_root)
805                                 if not info is None:
806                                         bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
807                         return bouquets
808                 return None
809
810         def keyNumber0(self, num):
811                 if len(self.servicePath) > 1:
812                         self.keyGoUp()
813                 else:
814                         self.keyNumberGlobal(num)
815
816         def keyGoUp(self):
817                 if len(self.servicePath) > 1:
818                         if self.isBasePathEqual(self.bouquet_root):
819                                 self.showFavourites()
820                         else:
821                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
822                                 if self.isBasePathEqual(ref):
823                                         self.showSatellites()
824                                 else:
825                                         ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
826                                         if self.isBasePathEqual(ref):
827                                                 self.showProviders()
828                                         else:
829                                                 self.showAllServices()
830
831 HISTORYSIZE = 20
832
833 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
834         def __init__(self, session):
835                 ChannelSelectionBase.__init__(self,session)
836                 ChannelSelectionEdit.__init__(self)
837                 ChannelSelectionEPG.__init__(self)
838
839                 #config for lastservice
840                 config.tv = ConfigSubsection();
841                 config.tv.lastservice = configElement("config.tv.lastservice", configText, "", 0);
842                 config.tv.lastroot = configElement("config.tv.lastroot", configText, "", 0);
843
844                 self["actions"] = ActionMap(["OkCancelActions"],
845                         {
846                                 "cancel": self.cancel,
847                                 "ok": self.channelSelected,
848                         })
849                 self.onShown.append(self.__onShown)
850
851                 self.lastChannelRootTimer = eTimer()
852                 self.lastChannelRootTimer.timeout.get().append(self.__onCreate)
853                 self.lastChannelRootTimer.start(100,True)
854
855                 self.history = [ ]
856                 self.history_pos = 0
857
858         def __onCreate(self):
859                 self.setTvMode()
860                 self.restoreRoot()
861                 lastservice=eServiceReference(config.tv.lastservice.value)
862                 if lastservice.valid():
863                         self.setCurrentSelection(lastservice)
864                         self.zap()
865
866         def __onShown(self):
867                 self.recallBouquetMode()
868                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
869                 if ref is not None and ref.valid() and ref.getPath() == "":
870                         self.servicelist.setPlayableIgnoreService(ref)
871                 else:
872                         self.servicelist.setPlayableIgnoreService(eServiceReference())
873
874         def channelSelected(self):
875                 ref = self.getCurrentSelection()
876                 if self.movemode:
877                         self.toggleMoveMarked()
878                 elif (ref.flags & 7) == 7:
879                         self.enterPath(ref)
880                 elif self.bouquet_mark_edit:
881                         self.doMark()
882                 else:
883                         self.zap()
884                         self.close(ref)
885
886         #called from infoBar and channelSelected
887         def zap(self):
888                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
889                 nref = self.getCurrentSelection()
890                 if ref is None or ref != nref:
891                         self.session.nav.playService(nref)
892                 self.saveRoot()
893                 self.saveChannel()
894                 if self.servicePath is not None:
895                         tmp=self.servicePath[:]
896                         tmp.append(nref)
897                         try:
898                                 del self.history[self.history_pos+1:]
899                         except:
900                                 pass
901                         self.history.append(tmp)
902                         hlen = len(self.history)
903                         if hlen > HISTORYSIZE:
904                                 del self.history[0]
905                                 hlen -= 1
906                         self.history_pos = hlen-1
907
908         def historyBack(self):
909                 hlen = len(self.history)
910                 if hlen > 1 and self.history_pos > 0:
911                         self.history_pos -= 1
912                         self.setHistoryPath()
913
914         def historyNext(self):
915                 hlen = len(self.history)
916                 if hlen > 1 and self.history_pos < (hlen-1):
917                         self.history_pos += 1
918                         self.setHistoryPath()
919
920         def setHistoryPath(self):
921                 path = self.history[self.history_pos][:]
922                 ref = path.pop()
923                 del self.servicePath[:]
924                 self.servicePath += path
925                 self.saveRoot()
926                 plen = len(path)
927                 root = path[plen-1]
928                 if self.getRoot() != root:
929                         self.setRoot(root)
930                 self.session.nav.playService(ref)
931                 self.setCurrentSelection(ref)
932                 self.saveChannel()
933
934         def saveRoot(self):
935                 path = ''
936                 for i in self.servicePathTV:
937                         path += i.toString()
938                         path += ';'
939                 if len(path) and path != config.tv.lastroot.value:
940                         config.tv.lastroot.value = path
941                         config.tv.lastroot.save()
942
943         def restoreRoot(self):
944                 self.clearPath()
945                 re = compile('.+?;')
946                 tmp = re.findall(config.tv.lastroot.value)
947                 cnt = 0
948                 for i in tmp:
949                         self.servicePathTV.append(eServiceReference(i[:len(i)-1]))
950                         cnt += 1
951                 if cnt:
952                         path = self.servicePathTV.pop()
953                         self.enterPath(path)
954                 else:
955                         self.showFavourites()
956                         self.saveRoot()
957
958         def preEnterPath(self, refstr):
959                 if len(self.servicePathTV) and self.servicePathTV[0] != eServiceReference(refstr):
960                         pathstr = config.tv.lastroot.value
961                         if pathstr is not None and pathstr.find(refstr) == 0:
962                                 self.restoreRoot()
963                                 lastservice=eServiceReference(config.tv.lastservice.value)
964                                 if lastservice.valid():
965                                         self.setCurrentSelection(lastservice)
966                                 return True
967                 return False
968
969         def saveChannel(self):
970                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
971                 if ref is not None:
972                         refstr = ref.toString()
973                 else:
974                         refstr = ""
975                 if refstr != config.tv.lastservice.value:
976                         config.tv.lastservice.value = refstr
977                         config.tv.lastservice.save()
978
979         def recallPrevService(self):
980                 hlen = len(self.history)
981                 if hlen > 1:
982                         if self.history_pos == hlen-1:
983                                 tmp = self.history[self.history_pos]
984                                 self.history[self.history_pos] = self.history[self.history_pos-1]
985                                 self.history[self.history_pos-1] = tmp
986                         else:
987                                 tmp = self.history[self.history_pos+1]
988                                 self.history[self.history_pos+1] = self.history[self.history_pos]
989                                 self.history[self.history_pos] = tmp
990                         self.setHistoryPath()
991
992         def cancel(self):
993                 self.close(None)
994                 self.restoreRoot()
995                 lastservice=eServiceReference(config.tv.lastservice.value)
996                 if lastservice.valid() and self.getCurrentSelection() != lastservice:
997                         self.setCurrentSelection(lastservice)
998
999 from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord
1000
1001 class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord):
1002         def __init__(self, session):
1003                 Screen.__init__(self, session)
1004                 InfoBarEvent.__init__(self)
1005                 InfoBarServiceName.__init__(self)
1006                 InfoBarInstantRecord.__init__(self)
1007                 self["Clock"] = Clock()
1008
1009 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
1010         def __init__(self, session):
1011                 ChannelSelectionBase.__init__(self, session)
1012                 ChannelSelectionEdit.__init__(self)
1013                 ChannelSelectionEPG.__init__(self)
1014
1015                 config.radio = ConfigSubsection();
1016                 config.radio.lastservice = configElement("config.radio.lastservice", configText, "", 0);
1017                 config.radio.lastroot = configElement("config.radio.lastroot", configText, "", 0);
1018                 self.onLayoutFinish.append(self.onCreate)
1019
1020                 self.info = session.instantiateDialog(RadioInfoBar)
1021
1022                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1023                         {
1024                                 "keyTV": self.closeRadio,
1025                                 "keyRadio": self.closeRadio,
1026                                 "cancel": self.closeRadio,
1027                                 "ok": self.channelSelected,
1028                         })
1029
1030         def saveRoot(self):
1031                 path = ''
1032                 for i in self.servicePathRadio:
1033                         path += i.toString()
1034                         path += ';'
1035                 if len(path) and path != config.radio.lastroot.value:
1036                         config.radio.lastroot.value = path
1037                         config.radio.lastroot.save()
1038
1039         def restoreRoot(self):
1040                 self.clearPath()
1041                 re = compile('.+?;')
1042                 tmp = re.findall(config.radio.lastroot.value)
1043                 cnt = 0
1044                 for i in tmp:
1045                         self.servicePathRadio.append(eServiceReference(i[:len(i)-1]))
1046                         cnt += 1
1047                 if cnt:
1048                         path = self.servicePathRadio.pop()
1049                         self.enterPath(path)
1050                 else:
1051                         self.showFavourites()
1052                         self.saveRoot()
1053
1054         def preEnterPath(self, refstr):
1055                 if len(self.servicePathRadio) and self.servicePathRadio[0] != eServiceReference(refstr):
1056                         pathstr = config.radio.lastroot.value
1057                         if pathstr is not None and pathstr.find(refstr) == 0:
1058                                 self.restoreRoot()
1059                                 lastservice=eServiceReference(config.radio.lastservice.value)
1060                                 if lastservice.valid():
1061                                         self.setCurrentSelection(lastservice)
1062                                 return True
1063                 return False
1064
1065         def onCreate(self):
1066                 self.setRadioMode()
1067                 self.restoreRoot()
1068                 lastservice=eServiceReference(config.radio.lastservice.value)
1069                 if lastservice.valid():
1070                         self.servicelist.setCurrent(lastservice)
1071                         self.session.nav.playService(lastservice)
1072                         self.servicelist.setPlayableIgnoreService(lastservice)
1073                 self.info.show()
1074
1075         def channelSelected(self): # just return selected service
1076                 ref = self.getCurrentSelection()
1077                 if self.movemode:
1078                         self.toggleMoveMarked()
1079                 elif (ref.flags & 7) == 7:
1080                         self.enterPath(ref)
1081                 elif self.bouquet_mark_edit:
1082                         self.doMark()
1083                 else:
1084                         playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1085                         if playingref is None or playingref != ref:
1086                                 self.session.nav.playService(ref)
1087                                 self.servicelist.setPlayableIgnoreService(ref)
1088                                 config.radio.lastservice.value = ref.toString()
1089                                 config.radio.lastservice.save()
1090                         self.saveRoot()
1091
1092         def closeRadio(self):
1093                 self.info.hide()
1094                 #set previous tv service
1095                 lastservice=eServiceReference(config.tv.lastservice.value)
1096                 self.session.nav.playService(lastservice)
1097                 self.close(None)
1098
1099 class SimpleChannelSelection(ChannelSelectionBase):
1100         def __init__(self, session, title):
1101                 ChannelSelectionBase.__init__(self, session)
1102                 self.title = title
1103                 self.onShown.append(self.__onExecCallback)
1104
1105                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1106                         {
1107                                 "cancel": self.close,
1108                                 "ok": self.channelSelected,
1109                                 "keyRadio": self.setModeRadio,
1110                                 "keyTV": self.setModeTv,
1111                         })
1112
1113         def __onExecCallback(self):
1114                 self.setTitle(self.title)
1115                 self.setModeTv()
1116
1117         def channelSelected(self): # just return selected service
1118                 ref = self.getCurrentSelection()
1119                 if (ref.flags & 7) == 7:
1120                         self.enterPath(ref)
1121                 else:
1122                         ref = self.getCurrentSelection()
1123                         self.close(ref)
1124
1125         def setModeTv(self):
1126                 self.setTvMode()
1127                 self.showFavourites()
1128
1129         def setModeRadio(self):
1130                 self.setRadioMode()
1131                 self.showFavourites()