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