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