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