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