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