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