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